From ef592032b346c57302deb3f00679a095c48d41d8 Mon Sep 17 00:00:00 2001 From: azyges Date: Tue, 25 Nov 2025 07:14:59 +0900 Subject: [PATCH] init 2 --- .gitmodules | 15 +- LightlessSync.sln | 73 +- LightlessSync/FileCache/FileCacheManager.cs | 2 + .../FileCache/TransientResourceManager.cs | 191 +- .../Interop/Ipc/IpcCallerPenumbra.cs | 251 +- .../Interop/Ipc/TextureConversionJob.cs | 21 + .../ChatConfigService.cs | 14 + .../Configurations/ChatConfig.cs | 15 + .../Configurations/LightlessConfig.cs | 2 + .../Configurations/PlayerPerformanceConfig.cs | 6 + LightlessSync/LightlessSync.csproj | 20 +- .../Data/FileReplacementDataComparer.cs | 46 +- .../Factories/FileDownloadManagerFactory.cs | 21 +- .../Factories/GameObjectHandlerFactory.cs | 23 +- .../PlayerData/Factories/PairFactory.cs | 71 +- .../Factories/PairHandlerFactory.cs | 55 - .../PlayerData/Handlers/PairHandler.cs | 775 ----- .../Pairs/IPairPerformanceSubject.cs | 16 + LightlessSync/PlayerData/Pairs/Pair.cs | 239 +- .../PlayerData/Pairs/PairCoordinator.cs | 553 ++++ .../PlayerData/Pairs/PairHandlerAdapter.cs | 1835 +++++++++++ .../PlayerData/Pairs/PairHandlerRegistry.cs | 493 +++ LightlessSync/PlayerData/Pairs/PairLedger.cs | 293 ++ LightlessSync/PlayerData/Pairs/PairManager.cs | 944 +++--- LightlessSync/PlayerData/Pairs/PairState.cs | 149 + .../PlayerData/Pairs/PairStateCache.cs | 118 + .../Pairs/VisibleUserDataDistributor.cs | 190 +- .../Services/CacheCreationService.cs | 33 +- LightlessSync/Plugin.cs | 105 +- .../ActorTracking/ActorObjectService.cs | 754 +++++ .../Services/BroadcastScanningService.cs | 20 +- .../Services/CharaData/CharaDataManager.cs | 11 +- LightlessSync/Services/CharacterAnalyzer.cs | 52 +- LightlessSync/Services/Chat/ChatModels.cs | 23 + .../Services/Chat/ZoneChatService.cs | 1131 +++++++ LightlessSync/Services/ContextMenuService.cs | 125 +- LightlessSync/Services/DalamudUtilService.cs | 102 +- .../Services/LightlessGroupProfileData.cs | 20 +- .../Services/LightlessProfileData.cs | 20 + .../Services/LightlessProfileManager.cs | 179 +- .../Services/LightlessUserProfileData.cs | 21 +- LightlessSync/Services/Mediator/Messages.cs | 23 +- LightlessSync/Services/NameplateHandler.cs | 20 +- LightlessSync/Services/NameplateService.cs | 13 +- LightlessSync/Services/NotificationService.cs | 33 +- LightlessSync/Services/PairRequestService.cs | 79 +- .../Services/PlayerPerformanceService.cs | 129 +- .../ServerConfigurationManager.cs | 7 + .../TextureCompression/TexFileHelper.cs | 282 ++ .../TextureCompressionCapabilities.cs | 58 + .../TextureCompressionRequest.cs | 8 + .../TextureCompressionService.cs | 330 ++ .../TextureCompressionTarget.cs | 10 + .../TextureDownscaleService.cs | 955 ++++++ .../TextureCompression/TextureMapKind.cs | 13 + .../TextureMetadataHelper.cs | 549 ++++ .../TextureUsageCategory.cs | 16 + LightlessSync/Services/UiFactory.cs | 116 +- LightlessSync/Services/UiService.cs | 106 +- LightlessSync/UI/BroadcastUI.cs | 10 +- LightlessSync/UI/CharaDataHubUi.McdOnline.cs | 7 +- LightlessSync/UI/CharaDataHubUi.cs | 9 +- LightlessSync/UI/CompactUI.cs | 384 ++- LightlessSync/UI/Components/DrawFolderBase.cs | 63 +- .../UI/Components/DrawFolderGroup.cs | 21 +- LightlessSync/UI/Components/DrawFolderTag.cs | 182 +- .../UI/Components/DrawGroupedGroupFolder.cs | 44 +- LightlessSync/UI/Components/DrawUserPair.cs | 74 +- .../Components/Popup/BanUserPopupHandler.cs | 7 +- .../UI/Components/SelectPairForTagUi.cs | 2 +- .../UI/Components/SelectSyncshellForTagUi.cs | 2 +- LightlessSync/UI/DataAnalysisUi.cs | 2913 +++++++++++++---- LightlessSync/UI/DrawEntityFactory.cs | 188 +- LightlessSync/UI/DtrEntry.cs | 18 +- LightlessSync/UI/EditProfileUi.Group.cs | 701 ++++ LightlessSync/UI/EditProfileUi.cs | 1453 ++++++-- LightlessSync/UI/Handlers/IdDisplayHandler.cs | 163 +- LightlessSync/UI/Models/PairDisplayEntry.cs | 25 + LightlessSync/UI/Models/PairUiEntry.cs | 30 + LightlessSync/UI/Models/PairUiSnapshot.cs | 24 + .../UI/Models/VisiblePairSortMode.cs | 11 + LightlessSync/UI/PopoutProfileUi.cs | 15 +- .../UI/ProfileEditorLayoutCoordinator.cs | 84 + LightlessSync/UI/ProfileTags.cs | 25 +- LightlessSync/UI/Services/PairUiService.cs | 228 ++ LightlessSync/UI/SettingsUi.cs | 253 +- LightlessSync/UI/StandaloneProfileUi.cs | 1263 ++++++- LightlessSync/UI/Style/MainStyle.cs | 2 +- LightlessSync/UI/Style/Selune.cs | 1006 ++++++ LightlessSync/UI/SyncshellAdminUI.cs | 262 +- LightlessSync/UI/SyncshellFinderUI.cs | 14 +- LightlessSync/UI/Tags/ProfileTagDefinition.cs | 30 + LightlessSync/UI/Tags/ProfileTagRenderer.cs | 226 ++ LightlessSync/UI/Tags/ProfileTagService.cs | 131 + LightlessSync/UI/TopTabMenu.cs | 137 +- LightlessSync/UI/UIColors.cs | 5 + LightlessSync/UI/UISharedService.cs | 128 +- LightlessSync/UI/ZoneChatUi.cs | 1101 +++++++ LightlessSync/Utils/Crypto.cs | 26 +- LightlessSync/Utils/SeStringUtils.cs | 440 +++ LightlessSync/Utils/VariousExtensions.cs | 24 +- .../WebAPI/Files/FileDownloadManager.cs | 90 +- .../WebAPI/Files/FileTransferOrchestrator.cs | 140 +- .../WebAPI/Files/FileUploadManager.cs | 1 + .../SignalR/ApIController.Functions.Users.cs | 33 +- .../ApiController.Functions.Callbacks.cs | 48 +- LightlessSync/WebAPI/SignalR/ApiController.cs | 231 +- LightlessSync/lib/DirectXTexC.dll | Bin 0 -> 983552 bytes LightlessSync/lib/OtterTex.dll | Bin 0 -> 42496 bytes LightlessSync/packages.lock.json | 49 +- PenumbraAPI | 1 - 111 files changed, 20622 insertions(+), 3476 deletions(-) create mode 100644 LightlessSync/Interop/Ipc/TextureConversionJob.cs create mode 100644 LightlessSync/LightlessConfiguration/ChatConfigService.cs create mode 100644 LightlessSync/LightlessConfiguration/Configurations/ChatConfig.cs delete mode 100644 LightlessSync/PlayerData/Factories/PairHandlerFactory.cs delete mode 100644 LightlessSync/PlayerData/Handlers/PairHandler.cs create mode 100644 LightlessSync/PlayerData/Pairs/IPairPerformanceSubject.cs create mode 100644 LightlessSync/PlayerData/Pairs/PairCoordinator.cs create mode 100644 LightlessSync/PlayerData/Pairs/PairHandlerAdapter.cs create mode 100644 LightlessSync/PlayerData/Pairs/PairHandlerRegistry.cs create mode 100644 LightlessSync/PlayerData/Pairs/PairLedger.cs create mode 100644 LightlessSync/PlayerData/Pairs/PairState.cs create mode 100644 LightlessSync/PlayerData/Pairs/PairStateCache.cs create mode 100644 LightlessSync/Services/ActorTracking/ActorObjectService.cs create mode 100644 LightlessSync/Services/Chat/ChatModels.cs create mode 100644 LightlessSync/Services/Chat/ZoneChatService.cs create mode 100644 LightlessSync/Services/LightlessProfileData.cs create mode 100644 LightlessSync/Services/TextureCompression/TexFileHelper.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureCompressionCapabilities.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureCompressionRequest.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureCompressionService.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureCompressionTarget.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureDownscaleService.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureMapKind.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureMetadataHelper.cs create mode 100644 LightlessSync/Services/TextureCompression/TextureUsageCategory.cs create mode 100644 LightlessSync/UI/EditProfileUi.Group.cs create mode 100644 LightlessSync/UI/Models/PairDisplayEntry.cs create mode 100644 LightlessSync/UI/Models/PairUiEntry.cs create mode 100644 LightlessSync/UI/Models/PairUiSnapshot.cs create mode 100644 LightlessSync/UI/Models/VisiblePairSortMode.cs create mode 100644 LightlessSync/UI/ProfileEditorLayoutCoordinator.cs create mode 100644 LightlessSync/UI/Services/PairUiService.cs create mode 100644 LightlessSync/UI/Style/Selune.cs create mode 100644 LightlessSync/UI/Tags/ProfileTagDefinition.cs create mode 100644 LightlessSync/UI/Tags/ProfileTagRenderer.cs create mode 100644 LightlessSync/UI/Tags/ProfileTagService.cs create mode 100644 LightlessSync/UI/ZoneChatUi.cs create mode 100644 LightlessSync/lib/DirectXTexC.dll create mode 100644 LightlessSync/lib/OtterTex.dll delete mode 160000 PenumbraAPI diff --git a/.gitmodules b/.gitmodules index fe64c7f..7879cd2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,15 @@ [submodule "LightlessAPI"] path = LightlessAPI url = https://git.lightless-sync.org/Lightless-Sync/LightlessAPI.git -[submodule "PenumbraAPI"] - path = PenumbraAPI - url = https://github.com/Ottermandias/Penumbra.Api.git +[submodule "Penumbra.GameData"] + path = Penumbra.GameData + url = https://github.com/Ottermandias/Penumbra.GameData +[submodule "Penumbra.Api"] + path = Penumbra.Api + url = https://github.com/Ottermandias/Penumbra.Api +[submodule "Penumbra.String"] + path = Penumbra.String + url = https://github.com/Ottermandias/Penumbra.String +[submodule "OtterGui"] + path = OtterGui + url = https://github.com/Ottermandias/OtterGui diff --git a/LightlessSync.sln b/LightlessSync.sln index 5b7ca3c..6aba7e9 100644 --- a/LightlessSync.sln +++ b/LightlessSync.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.32328.378 @@ -12,7 +11,17 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightlessSync", "LightlessS EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LightlessSync.API", "LightlessAPI\LightlessSyncAPI\LightlessSync.API.csproj", "{A4E42AFA-5045-7E81-937F-3A320AC52987}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Penumbra.Api", "PenumbraAPI\Penumbra.Api.csproj", "{C104F6BE-9CC4-9CF7-271C-5C3A1F646601}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Penumbra.GameData", "Penumbra.GameData\Penumbra.GameData.csproj", "{CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Penumbra.Api", "Penumbra.Api\Penumbra.Api.csproj", "{65ACC53A-1D72-40D4-A99E-7D451D87E182}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Penumbra.String", "Penumbra.String\Penumbra.String.csproj", "{4D466894-0F1E-4808-A3E8-3FC9DE954AC6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OtterGui", "OtterGui\OtterGui.csproj", "{719723E1-8218-495A-98BA-4D0BDF7822EB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OtterGui", "OtterGui", "{F30CFB00-531B-5698-C50F-38FBF3471340}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OtterGuiInternal", "OtterGui\OtterGuiInternal\OtterGuiInternal.csproj", "{DF590F45-F26C-4337-98DE-367C97253125}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -22,34 +31,70 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.ActiveCfg = Release|x64 - {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.Build.0 = Release|x64 + {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.ActiveCfg = Debug|x64 + {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|Any CPU.Build.0 = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|x64.ActiveCfg = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Debug|x64.Build.0 = Debug|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|Any CPU.ActiveCfg = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|Any CPU.Build.0 = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|x64.ActiveCfg = Release|x64 {BB929046-4CD2-B174-EBAA-C756AC3AC8DA}.Release|x64.Build.0 = Release|x64 - {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.Build.0 = Release|Any CPU + {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|Any CPU.Build.0 = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|x64.ActiveCfg = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Debug|x64.Build.0 = Debug|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|Any CPU.ActiveCfg = Release|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|Any CPU.Build.0 = Release|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|x64.ActiveCfg = Release|Any CPU {A4E42AFA-5045-7E81-937F-3A320AC52987}.Release|x64.Build.0 = Release|Any CPU - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|Any CPU.ActiveCfg = Debug|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|Any CPU.Build.0 = Debug|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|x64.ActiveCfg = Debug|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Debug|x64.Build.0 = Debug|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|Any CPU.ActiveCfg = Release|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|Any CPU.Build.0 = Release|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|x64.ActiveCfg = Release|x64 - {C104F6BE-9CC4-9CF7-271C-5C3A1F646601}.Release|x64.Build.0 = Release|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Debug|Any CPU.ActiveCfg = Debug|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Debug|Any CPU.Build.0 = Debug|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Debug|x64.ActiveCfg = Debug|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Debug|x64.Build.0 = Debug|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Release|Any CPU.ActiveCfg = Release|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Release|Any CPU.Build.0 = Release|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Release|x64.ActiveCfg = Release|x64 + {CCB659C7-3D2D-4FB1-856E-98FDA8E5A6D3}.Release|x64.Build.0 = Release|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Debug|Any CPU.ActiveCfg = Debug|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Debug|Any CPU.Build.0 = Debug|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Debug|x64.ActiveCfg = Debug|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Debug|x64.Build.0 = Debug|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Release|Any CPU.ActiveCfg = Release|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Release|Any CPU.Build.0 = Release|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Release|x64.ActiveCfg = Release|x64 + {65ACC53A-1D72-40D4-A99E-7D451D87E182}.Release|x64.Build.0 = Release|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Debug|Any CPU.ActiveCfg = Debug|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Debug|Any CPU.Build.0 = Debug|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Debug|x64.ActiveCfg = Debug|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Debug|x64.Build.0 = Debug|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Release|Any CPU.ActiveCfg = Release|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Release|Any CPU.Build.0 = Release|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Release|x64.ActiveCfg = Release|x64 + {4D466894-0F1E-4808-A3E8-3FC9DE954AC6}.Release|x64.Build.0 = Release|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Debug|Any CPU.ActiveCfg = Debug|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Debug|Any CPU.Build.0 = Debug|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Debug|x64.ActiveCfg = Debug|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Debug|x64.Build.0 = Debug|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Release|Any CPU.ActiveCfg = Release|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Release|Any CPU.Build.0 = Release|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Release|x64.ActiveCfg = Release|x64 + {719723E1-8218-495A-98BA-4D0BDF7822EB}.Release|x64.Build.0 = Release|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Debug|Any CPU.ActiveCfg = Debug|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Debug|Any CPU.Build.0 = Debug|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Debug|x64.ActiveCfg = Debug|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Debug|x64.Build.0 = Debug|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Release|Any CPU.ActiveCfg = Release|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Release|Any CPU.Build.0 = Release|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Release|x64.ActiveCfg = Release|x64 + {DF590F45-F26C-4337-98DE-367C97253125}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {719723E1-8218-495A-98BA-4D0BDF7822EB} = {F30CFB00-531B-5698-C50F-38FBF3471340} + {DF590F45-F26C-4337-98DE-367C97253125} = {F30CFB00-531B-5698-C50F-38FBF3471340} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B17E85B1-5F60-4440-9F9A-3DDE877E8CDF} EndGlobalSection diff --git a/LightlessSync/FileCache/FileCacheManager.cs b/LightlessSync/FileCache/FileCacheManager.cs index 7ee6c99..cda255c 100644 --- a/LightlessSync/FileCache/FileCacheManager.cs +++ b/LightlessSync/FileCache/FileCacheManager.cs @@ -823,6 +823,8 @@ public sealed class FileCacheManager : IHostedService _logger.LogInformation("Started FileCacheManager"); + _lightlessMediator.Publish(new FileCacheInitializedMessage()); + return Task.CompletedTask; } diff --git a/LightlessSync/FileCache/TransientResourceManager.cs b/LightlessSync/FileCache/TransientResourceManager.cs index 6a9575a..f808fa6 100644 --- a/LightlessSync/FileCache/TransientResourceManager.cs +++ b/LightlessSync/FileCache/TransientResourceManager.cs @@ -3,11 +3,17 @@ using LightlessSync.LightlessConfiguration; using LightlessSync.LightlessConfiguration.Configurations; using LightlessSync.PlayerData.Data; using LightlessSync.PlayerData.Handlers; +using LightlessSync.PlayerData.Factories; using LightlessSync.Services; +using LightlessSync.Services.ActorTracking; using LightlessSync.Services.Mediator; using LightlessSync.Utils; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq; +using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace LightlessSync.FileCache; @@ -17,21 +23,29 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase private readonly HashSet _cachedHandledPaths = new(StringComparer.Ordinal); private readonly TransientConfigService _configurationService; private readonly DalamudUtilService _dalamudUtil; + private readonly ActorObjectService _actorObjectService; + private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; + private readonly object _ownedHandlerLock = new(); private readonly string[] _handledFileTypes = ["tmb", "pap", "avfx", "atex", "sklb", "eid", "phyb", "scd", "skp", "shpk", "kdb"]; private readonly string[] _handledRecordingFileTypes = ["tex", "mdl", "mtrl"]; private readonly HashSet _playerRelatedPointers = []; - private ConcurrentDictionary _cachedFrameAddresses = []; + private readonly Dictionary _ownedHandlers = new(); + private ConcurrentDictionary _cachedFrameAddresses = new(); private ConcurrentDictionary>? _semiTransientResources = null; private uint _lastClassJobId = uint.MaxValue; public bool IsTransientRecording { get; private set; } = false; public TransientResourceManager(ILogger logger, TransientConfigService configurationService, - DalamudUtilService dalamudUtil, LightlessMediator mediator) : base(logger, mediator) + DalamudUtilService dalamudUtil, LightlessMediator mediator, ActorObjectService actorObjectService, GameObjectHandlerFactory gameObjectHandlerFactory) : base(logger, mediator) { _configurationService = configurationService; _dalamudUtil = dalamudUtil; + _actorObjectService = actorObjectService; + _gameObjectHandlerFactory = gameObjectHandlerFactory; Mediator.Subscribe(this, Manager_PenumbraResourceLoadEvent); + Mediator.Subscribe(this, msg => HandleActorTracked(msg.Descriptor)); + Mediator.Subscribe(this, msg => HandleActorUntracked(msg.Descriptor)); Mediator.Subscribe(this, (_) => Manager_PenumbraModSettingChanged()); Mediator.Subscribe(this, (_) => DalamudUtil_FrameworkUpdate()); Mediator.Subscribe(this, (msg) => @@ -44,6 +58,11 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase if (!msg.OwnedObject) return; _playerRelatedPointers.Remove(msg.GameObjectHandler); }); + + foreach (var descriptor in _actorObjectService.PlayerDescriptors) + { + HandleActorTracked(descriptor); + } } private TransientConfig.TransientPlayerConfig PlayerConfig @@ -241,16 +260,46 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase TransientResources.Clear(); SemiTransientResources.Clear(); + + lock (_ownedHandlerLock) + { + foreach (var handler in _ownedHandlers.Values) + { + handler.Dispose(); + } + _ownedHandlers.Clear(); + } } private void DalamudUtil_FrameworkUpdate() { - _cachedFrameAddresses = new(_playerRelatedPointers.Where(k => k.Address != nint.Zero).ToDictionary(c => c.Address, c => c.ObjectKind)); lock (_cacheAdditionLock) { _cachedHandledPaths.Clear(); } + var activeDescriptors = new Dictionary(); + foreach (var descriptor in _actorObjectService.PlayerDescriptors) + { + if (TryResolveObjectKind(descriptor, out var resolvedKind)) + { + activeDescriptors[descriptor.Address] = resolvedKind; + } + } + + foreach (var address in _cachedFrameAddresses.Keys.ToList()) + { + if (!activeDescriptors.ContainsKey(address)) + { + _cachedFrameAddresses.TryRemove(address, out _); + } + } + + foreach (var descriptor in activeDescriptors) + { + _cachedFrameAddresses[descriptor.Key] = descriptor.Value; + } + if (_lastClassJobId != _dalamudUtil.ClassJobId) { _lastClassJobId = _dalamudUtil.ClassJobId; @@ -259,16 +308,15 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase value?.Clear(); } - // reload config for current new classjob PlayerConfig.JobSpecificCache.TryGetValue(_dalamudUtil.ClassJobId, out var jobSpecificData); SemiTransientResources[ObjectKind.Player] = PlayerConfig.GlobalPersistentCache.Concat(jobSpecificData ?? []).ToHashSet(StringComparer.OrdinalIgnoreCase); PlayerConfig.JobSpecificPetCache.TryGetValue(_dalamudUtil.ClassJobId, out var petSpecificData); SemiTransientResources[ObjectKind.Pet] = [.. petSpecificData ?? []]; } - foreach (var kind in Enum.GetValues(typeof(ObjectKind))) + foreach (var kind in Enum.GetValues(typeof(ObjectKind)).Cast()) { - if (!_cachedFrameAddresses.Any(k => k.Value == (ObjectKind)kind) && TransientResources.Remove((ObjectKind)kind, out _)) + if (!_cachedFrameAddresses.Any(k => k.Value == kind) && TransientResources.Remove(kind, out _)) { Logger.LogDebug("Object not present anymore: {kind}", kind.ToString()); } @@ -292,6 +340,116 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase _semiTransientResources = null; } + private static bool TryResolveObjectKind(ActorObjectService.ActorDescriptor descriptor, out ObjectKind resolvedKind) + { + if (descriptor.OwnedKind is ObjectKind ownedKind) + { + resolvedKind = ownedKind; + return true; + } + + if (descriptor.ObjectKind == DalamudObjectKind.Player) + { + resolvedKind = ObjectKind.Player; + return true; + } + + resolvedKind = default; + return false; + } + + private void HandleActorTracked(ActorObjectService.ActorDescriptor descriptor) + { + if (!TryResolveObjectKind(descriptor, out var resolvedKind)) + return; + + if (Logger.IsEnabled(LogLevel.Debug)) + { + Logger.LogDebug("ActorObject tracked: {kind} addr={address:X} name={name}", resolvedKind, descriptor.Address, descriptor.Name); + } + + _cachedFrameAddresses[descriptor.Address] = resolvedKind; + + if (descriptor.OwnedKind is not ObjectKind ownedKind) + return; + + lock (_ownedHandlerLock) + { + if (_ownedHandlers.ContainsKey(descriptor.Address)) + return; + + _ = CreateOwnedHandlerAsync(descriptor, ownedKind); + } + } + + private void HandleActorUntracked(ActorObjectService.ActorDescriptor descriptor) + { + if (Logger.IsEnabled(LogLevel.Debug)) + { + var kindLabel = descriptor.OwnedKind?.ToString() + ?? (descriptor.ObjectKind == DalamudObjectKind.Player ? ObjectKind.Player.ToString() : ""); + Logger.LogDebug("ActorObject untracked: addr={address:X} name={name} kind={kind}", descriptor.Address, descriptor.Name, kindLabel); + } + + _cachedFrameAddresses.TryRemove(descriptor.Address, out _); + + if (descriptor.OwnedKind is not ObjectKind) + return; + + lock (_ownedHandlerLock) + { + if (_ownedHandlers.Remove(descriptor.Address, out var handler)) + { + handler.Dispose(); + } + } + } + + private async Task CreateOwnedHandlerAsync(ActorObjectService.ActorDescriptor descriptor, ObjectKind kind) + { + try + { + var handler = await _gameObjectHandlerFactory.Create( + kind, + () => + { + if (!string.IsNullOrEmpty(descriptor.HashedContentId) && + _actorObjectService.TryGetActorByHash(descriptor.HashedContentId, out var current) && + current.OwnedKind == kind) + { + return current.Address; + } + + return descriptor.Address; + }, + true).ConfigureAwait(false); + + if (handler.Address == IntPtr.Zero) + { + handler.Dispose(); + return; + } + + lock (_ownedHandlerLock) + { + if (!_cachedFrameAddresses.ContainsKey(descriptor.Address)) + { + Logger.LogDebug("ActorObject handler discarded (stale): addr={address:X}", descriptor.Address); + handler.Dispose(); + return; + } + + _ownedHandlers[descriptor.Address] = handler; + } + + Logger.LogDebug("ActorObject handler created: {kind} addr={address:X}", kind, descriptor.Address); + } + catch (Exception ex) + { + Logger.LogError(ex, "Failed to create owned handler for {kind} at {address:X}", kind, descriptor.Address); + } + } + private void Manager_PenumbraResourceLoadEvent(PenumbraResourceLoadMessage msg) { var gamePath = msg.GamePath.ToLowerInvariant(); @@ -383,21 +541,30 @@ public sealed class TransientResourceManager : DisposableMediatorSubscriberBase private void SendTransients(nint gameObject, ObjectKind objectKind) { + _sendTransientCts.Cancel(); + _sendTransientCts = new(); + var token = _sendTransientCts.Token; + _ = Task.Run(async () => { - _sendTransientCts?.Cancel(); - _sendTransientCts?.Dispose(); - _sendTransientCts = new(); - var token = _sendTransientCts.Token; - await Task.Delay(TimeSpan.FromSeconds(5), token).ConfigureAwait(false); - foreach (var kvp in TransientResources) + try { + await Task.Delay(TimeSpan.FromSeconds(5), token).ConfigureAwait(false); + if (TransientResources.TryGetValue(objectKind, out var values) && values.Any()) { Logger.LogTrace("Sending Transients for {kind}", objectKind); Mediator.Publish(new TransientResourceChangedMessage(gameObject)); } } + catch (TaskCanceledException) + { + + } + catch (System.OperationCanceledException) + { + + } }); } diff --git a/LightlessSync/Interop/Ipc/IpcCallerPenumbra.cs b/LightlessSync/Interop/Ipc/IpcCallerPenumbra.cs index fd92fca..2ecc56b 100644 --- a/LightlessSync/Interop/Ipc/IpcCallerPenumbra.cs +++ b/LightlessSync/Interop/Ipc/IpcCallerPenumbra.cs @@ -2,12 +2,18 @@ using LightlessSync.LightlessConfiguration.Models; using LightlessSync.PlayerData.Handlers; using LightlessSync.Services; +using LightlessSync.Services.ActorTracking; using LightlessSync.Services.Mediator; using Microsoft.Extensions.Logging; using Penumbra.Api.Enums; using Penumbra.Api.Helpers; using Penumbra.Api.IpcSubscribers; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace LightlessSync.Interop.Ipc; @@ -17,6 +23,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa private readonly DalamudUtilService _dalamudUtil; private readonly LightlessMediator _lightlessMediator; private readonly RedrawManager _redrawManager; + private readonly ActorObjectService _actorObjectService; private bool _shownPenumbraUnavailable = false; private string? _penumbraModDirectory; public string? ModDirectory @@ -33,6 +40,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa } private readonly ConcurrentDictionary _penumbraRedrawRequests = new(); + private readonly ConcurrentDictionary _trackedActors = new(); private readonly EventSubscriber _penumbraDispose; private readonly EventSubscriber _penumbraGameObjectResourcePathResolved; @@ -52,14 +60,19 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa private readonly GetModDirectory _penumbraResolveModDir; private readonly ResolvePlayerPathsAsync _penumbraResolvePaths; private readonly GetGameObjectResourcePaths _penumbraResourcePaths; + //private readonly GetPlayerResourcePaths _penumbraPlayerResourcePaths; + private readonly GetCollections _penumbraGetCollections; + private readonly ConcurrentDictionary _activeTemporaryCollections = new(); + private int _performedInitialCleanup; public IpcCallerPenumbra(ILogger logger, IDalamudPluginInterface pi, DalamudUtilService dalamudUtil, - LightlessMediator lightlessMediator, RedrawManager redrawManager) : base(logger, lightlessMediator) + LightlessMediator lightlessMediator, RedrawManager redrawManager, ActorObjectService actorObjectService) : base(logger, lightlessMediator) { _pi = pi; _dalamudUtil = dalamudUtil; _lightlessMediator = lightlessMediator; _redrawManager = redrawManager; + _actorObjectService = actorObjectService; _penumbraInit = Initialized.Subscriber(pi, PenumbraInit); _penumbraDispose = Disposed.Subscriber(pi, PenumbraDispose); _penumbraResolveModDir = new GetModDirectory(pi); @@ -71,6 +84,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa _penumbraCreateNamedTemporaryCollection = new CreateTemporaryCollection(pi); _penumbraRemoveTemporaryCollection = new DeleteTemporaryCollection(pi); _penumbraAssignTemporaryCollection = new AssignTemporaryCollection(pi); + _penumbraGetCollections = new GetCollections(pi); _penumbraResolvePaths = new ResolvePlayerPathsAsync(pi); _penumbraEnabled = new GetEnabledState(pi); _penumbraModSettingChanged = ModSettingChanged.Subscriber(pi, (change, arg1, arg, b) => @@ -80,6 +94,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa }); _penumbraConvertTextureFile = new ConvertTextureFile(pi); _penumbraResourcePaths = new GetGameObjectResourcePaths(pi); + //_penumbraPlayerResourcePaths = new GetPlayerResourcePaths(pi); _penumbraGameObjectResourcePathResolved = GameObjectResourcePathResolved.Subscriber(pi, ResourceLoaded); @@ -92,6 +107,46 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa }); Mediator.Subscribe(this, (msg) => _shownPenumbraUnavailable = false); + + Mediator.Subscribe(this, msg => + { + if (msg.Descriptor.Address != nint.Zero) + { + _trackedActors[(IntPtr)msg.Descriptor.Address] = 0; + } + }); + + Mediator.Subscribe(this, msg => + { + if (msg.Descriptor.Address != nint.Zero) + { + _trackedActors.TryRemove((IntPtr)msg.Descriptor.Address, out _); + } + }); + + Mediator.Subscribe(this, msg => + { + if (msg.GameObjectHandler.Address != nint.Zero) + { + _trackedActors[(IntPtr)msg.GameObjectHandler.Address] = 0; + } + }); + + Mediator.Subscribe(this, msg => + { + if (msg.GameObjectHandler.Address != nint.Zero) + { + _trackedActors.TryRemove((IntPtr)msg.GameObjectHandler.Address, out _); + } + }); + + foreach (var descriptor in _actorObjectService.PlayerDescriptors) + { + if (descriptor.Address != nint.Zero) + { + _trackedActors[(IntPtr)descriptor.Address] = 0; + } + } } public bool APIAvailable { get; private set; } = false; @@ -130,6 +185,11 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa NotificationType.Error)); } } + + if (APIAvailable) + { + ScheduleTemporaryCollectionCleanup(); + } } public void CheckModDirectory() @@ -144,6 +204,56 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa } } + private void ScheduleTemporaryCollectionCleanup() + { + if (Interlocked.Exchange(ref _performedInitialCleanup, 1) != 0) + return; + + _ = Task.Run(CleanupTemporaryCollectionsAsync); + } + + private async Task CleanupTemporaryCollectionsAsync() + { + if (!APIAvailable) + return; + + try + { + var collections = await _dalamudUtil.RunOnFrameworkThread(() => _penumbraGetCollections.Invoke()).ConfigureAwait(false); + foreach (var (collectionId, name) in collections) + { + if (!IsLightlessCollectionName(name)) + continue; + + if (_activeTemporaryCollections.ContainsKey(collectionId)) + continue; + + Logger.LogDebug("Cleaning up stale temporary collection {CollectionName} ({CollectionId})", name, collectionId); + var deleteResult = await _dalamudUtil.RunOnFrameworkThread(() => + { + var result = (PenumbraApiEc)_penumbraRemoveTemporaryCollection.Invoke(collectionId); + Logger.LogTrace("Cleanup RemoveTemporaryCollection result for {CollectionName} ({CollectionId}): {Result}", name, collectionId, result); + return result; + }).ConfigureAwait(false); + if (deleteResult == PenumbraApiEc.Success) + { + _activeTemporaryCollections.TryRemove(collectionId, out _); + } + else + { + Logger.LogDebug("Skipped removing temporary collection {CollectionName} ({CollectionId}). Result: {Result}", name, collectionId, deleteResult); + } + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Failed to clean up Penumbra temporary collections"); + } + } + + private static bool IsLightlessCollectionName(string? name) + => !string.IsNullOrEmpty(name) && name.StartsWith("Lightless_", StringComparison.Ordinal); + protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -169,58 +279,91 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa }).ConfigureAwait(false); } - public async Task ConvertTextureFiles(ILogger logger, Dictionary textures, IProgress<(string, int)> progress, CancellationToken token) + public async Task ConvertTextureFiles(ILogger logger, IReadOnlyList jobs, IProgress? progress, CancellationToken token) { - if (!APIAvailable) return; + if (!APIAvailable || jobs.Count == 0) + { + return; + } _lightlessMediator.Publish(new HaltScanMessage(nameof(ConvertTextureFiles))); - int currentTexture = 0; - foreach (var texture in textures) + + var totalJobs = jobs.Count; + var completedJobs = 0; + + try { - if (token.IsCancellationRequested) break; - - progress.Report((texture.Key, ++currentTexture)); - - logger.LogInformation("Converting Texture {path} to {type}", texture.Key, TextureType.Bc7Tex); - var convertTask = _penumbraConvertTextureFile.Invoke(texture.Key, texture.Key, TextureType.Bc7Tex, mipMaps: true); - await convertTask.ConfigureAwait(false); - if (convertTask.IsCompletedSuccessfully && texture.Value.Any()) + foreach (var job in jobs) { - foreach (var duplicatedTexture in texture.Value) + if (token.IsCancellationRequested) { - logger.LogInformation("Migrating duplicate {dup}", duplicatedTexture); - try + break; + } + + progress?.Report(new TextureConversionProgress(completedJobs, totalJobs, job)); + + logger.LogInformation("Converting texture {Input} -> {Output} ({Target})", job.InputFile, job.OutputFile, job.TargetType); + var convertTask = _penumbraConvertTextureFile.Invoke(job.InputFile, job.OutputFile, job.TargetType, job.IncludeMipMaps); + await convertTask.ConfigureAwait(false); + + if (convertTask.IsCompletedSuccessfully && job.DuplicateTargets is { Count: > 0 }) + { + foreach (var duplicate in job.DuplicateTargets) { - File.Copy(texture.Key, duplicatedTexture, overwrite: true); - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to copy duplicate {dup}", duplicatedTexture); + logger.LogInformation("Synchronizing duplicate {Duplicate}", duplicate); + try + { + File.Copy(job.OutputFile, duplicate, overwrite: true); + } + catch (Exception ex) + { + logger.LogError(ex, "Failed to copy duplicate {Duplicate}", duplicate); + } } } + + completedJobs++; } } - _lightlessMediator.Publish(new ResumeScanMessage(nameof(ConvertTextureFiles))); - - await _dalamudUtil.RunOnFrameworkThread(async () => + finally { - var gameObject = await _dalamudUtil.CreateGameObjectAsync(await _dalamudUtil.GetPlayerPointerAsync().ConfigureAwait(false)).ConfigureAwait(false); - _penumbraRedraw.Invoke(gameObject!.ObjectIndex, setting: RedrawType.Redraw); - }).ConfigureAwait(false); + _lightlessMediator.Publish(new ResumeScanMessage(nameof(ConvertTextureFiles))); + } + + if (completedJobs > 0 && !token.IsCancellationRequested) + { + await _dalamudUtil.RunOnFrameworkThread(async () => + { + var player = await _dalamudUtil.GetPlayerPointerAsync().ConfigureAwait(false); + if (player == null) + { + return; + } + + var gameObject = await _dalamudUtil.CreateGameObjectAsync(player).ConfigureAwait(false); + _penumbraRedraw.Invoke(gameObject!.ObjectIndex, setting: RedrawType.Redraw); + }).ConfigureAwait(false); + } } public async Task CreateTemporaryCollectionAsync(ILogger logger, string uid) { if (!APIAvailable) return Guid.Empty; - return await _dalamudUtil.RunOnFrameworkThread(() => + var (collectionId, collectionName) = await _dalamudUtil.RunOnFrameworkThread(() => { var collName = "Lightless_" + uid; _penumbraCreateNamedTemporaryCollection.Invoke(collName, collName, out var collId); logger.LogTrace("Creating Temp Collection {collName}, GUID: {collId}", collName, collId); - return collId; + return (collId, collName); }).ConfigureAwait(false); + if (collectionId != Guid.Empty) + { + _activeTemporaryCollections[collectionId] = collectionName; + } + + return collectionId; } public async Task>?> GetCharacterData(ILogger logger, GameObjectHandler handler) @@ -270,6 +413,10 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa var ret2 = _penumbraRemoveTemporaryCollection.Invoke(collId); logger.LogTrace("[{applicationId}] RemoveTemporaryCollection: {ret2}", applicationId, ret2); }).ConfigureAwait(false); + if (collId != Guid.Empty) + { + _activeTemporaryCollections.TryRemove(collId, out _); + } } public async Task<(string[] forward, string[][] reverse)> ResolvePathsAsync(string[] forward, string[] reverse) @@ -277,6 +424,31 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa return await _penumbraResolvePaths.Invoke(forward, reverse).ConfigureAwait(false); } + public async Task ConvertTextureFileDirectAsync(TextureConversionJob job, CancellationToken token) + { + if (!APIAvailable) return; + + token.ThrowIfCancellationRequested(); + + await _penumbraConvertTextureFile.Invoke(job.InputFile, job.OutputFile, job.TargetType, job.IncludeMipMaps) + .ConfigureAwait(false); + + if (job.DuplicateTargets is { Count: > 0 }) + { + foreach (var duplicate in job.DuplicateTargets) + { + try + { + File.Copy(job.OutputFile, duplicate, overwrite: true); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to copy duplicate {Duplicate} for texture conversion", duplicate); + } + } + } + } + public async Task SetManipulationDataAsync(ILogger logger, Guid applicationId, Guid collId, string manipulationData) { if (!APIAvailable) return; @@ -321,10 +493,26 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa private void ResourceLoaded(IntPtr ptr, string arg1, string arg2) { - if (ptr != IntPtr.Zero && string.Compare(arg1, arg2, ignoreCase: true, System.Globalization.CultureInfo.InvariantCulture) != 0) + if (ptr == IntPtr.Zero) + return; + + if (!_trackedActors.ContainsKey(ptr)) { - _lightlessMediator.Publish(new PenumbraResourceLoadMessage(ptr, arg1, arg2)); + var descriptor = _actorObjectService.PlayerDescriptors.FirstOrDefault(d => d.Address == ptr); + if (descriptor.Address != nint.Zero) + { + _trackedActors[ptr] = 0; + } + else + { + return; + } } + + if (string.Compare(arg1, arg2, ignoreCase: true, System.Globalization.CultureInfo.InvariantCulture) == 0) + return; + + _lightlessMediator.Publish(new PenumbraResourceLoadMessage(ptr, arg1, arg2)); } private void PenumbraDispose() @@ -338,6 +526,7 @@ public sealed class IpcCallerPenumbra : DisposableMediatorSubscriberBase, IIpcCa APIAvailable = true; ModDirectory = _penumbraResolveModDir.Invoke(); _lightlessMediator.Publish(new PenumbraInitializedMessage()); + ScheduleTemporaryCollectionCleanup(); _penumbraRedraw!.Invoke(0, setting: RedrawType.Redraw); } } diff --git a/LightlessSync/Interop/Ipc/TextureConversionJob.cs b/LightlessSync/Interop/Ipc/TextureConversionJob.cs new file mode 100644 index 0000000..2bbe9fd --- /dev/null +++ b/LightlessSync/Interop/Ipc/TextureConversionJob.cs @@ -0,0 +1,21 @@ +using Penumbra.Api.Enums; + +namespace LightlessSync.Interop.Ipc; + +/// +/// Represents a single texture conversion request, including optional duplicate targets. +/// +public sealed record TextureConversionJob( + string InputFile, + string OutputFile, + TextureType TargetType, + bool IncludeMipMaps = true, + IReadOnlyList? DuplicateTargets = null); + +/// +/// Progress payload for a texture conversion batch. +/// +/// Number of completed conversions. +/// Total number of conversions scheduled. +/// The job currently being processed. +public sealed record TextureConversionProgress(int Completed, int Total, TextureConversionJob CurrentJob); diff --git a/LightlessSync/LightlessConfiguration/ChatConfigService.cs b/LightlessSync/LightlessConfiguration/ChatConfigService.cs new file mode 100644 index 0000000..f91cfca --- /dev/null +++ b/LightlessSync/LightlessConfiguration/ChatConfigService.cs @@ -0,0 +1,14 @@ +using LightlessSync.LightlessConfiguration.Configurations; + +namespace LightlessSync.LightlessConfiguration; + +public sealed class ChatConfigService : ConfigurationServiceBase +{ + public const string ConfigName = "chatconfig.json"; + + public ChatConfigService(string configDir) : base(configDir) + { + } + + public override string ConfigurationName => ConfigName; +} diff --git a/LightlessSync/LightlessConfiguration/Configurations/ChatConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/ChatConfig.cs new file mode 100644 index 0000000..7812887 --- /dev/null +++ b/LightlessSync/LightlessConfiguration/Configurations/ChatConfig.cs @@ -0,0 +1,15 @@ +using System; + +namespace LightlessSync.LightlessConfiguration.Configurations; + +[Serializable] +public sealed class ChatConfig : ILightlessConfiguration +{ + public int Version { get; set; } = 1; + public bool AutoEnableChatOnLogin { get; set; } = false; + public bool ShowRulesOverlayOnOpen { get; set; } = true; + public bool ShowMessageTimestamps { get; set; } = true; + public float ChatWindowOpacity { get; set; } = .97f; + public bool IsWindowPinned { get; set; } = false; + public bool AutoOpenChatOnPluginLoad { get; set; } = false; +} diff --git a/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs index 929cbbc..478db89 100644 --- a/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs +++ b/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs @@ -2,6 +2,7 @@ using Dalamud.Game.Text; using LightlessSync.UtilsEnum.Enum; using LightlessSync.LightlessConfiguration.Models; using LightlessSync.UI; +using LightlessSync.UI.Models; using Microsoft.Extensions.Logging; namespace LightlessSync.LightlessConfiguration.Configurations; @@ -48,6 +49,7 @@ public class LightlessConfig : ILightlessConfiguration public int DownloadSpeedLimitInBytes { get; set; } = 0; public DownloadSpeeds DownloadSpeedType { get; set; } = DownloadSpeeds.MBps; public bool PreferNotesOverNamesForVisible { get; set; } = false; + public VisiblePairSortMode VisiblePairSortMode { get; set; } = VisiblePairSortMode.Default; public float ProfileDelay { get; set; } = 1.5f; public bool ProfilePopoutRight { get; set; } = false; public bool ProfilesAllowNsfw { get; set; } = false; diff --git a/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs index ca12006..7da9ac2 100644 --- a/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs +++ b/LightlessSync/LightlessConfiguration/Configurations/PlayerPerformanceConfig.cs @@ -4,6 +4,7 @@ public class PlayerPerformanceConfig : ILightlessConfiguration { public int Version { get; set; } = 1; public bool ShowPerformanceIndicator { get; set; } = true; + public bool ShowPerformanceUsageNextToName { get; set; } = false; public bool WarnOnExceedingThresholds { get; set; } = true; public bool WarnOnPreferredPermissionsExceedingThresholds { get; set; } = false; public int VRAMSizeWarningThresholdMiB { get; set; } = 375; @@ -16,4 +17,9 @@ public class PlayerPerformanceConfig : ILightlessConfiguration public bool PauseInInstanceDuty { get; set; } = false; public bool PauseWhilePerforming { get; set; } = true; public bool PauseInCombat { get; set; } = true; + public bool EnableNonIndexTextureMipTrim { get; set; } = false; + public bool EnableIndexTextureDownscale { get; set; } = false; + public int TextureDownscaleMaxDimension { get; set; } = 2048; + public bool OnlyDownscaleUncompressedTextures { get; set; } = true; + public bool KeepOriginalTextureFiles { get; set; } = false; } \ No newline at end of file diff --git a/LightlessSync/LightlessSync.csproj b/LightlessSync/LightlessSync.csproj index 726f2ef..ec722c5 100644 --- a/LightlessSync/LightlessSync.csproj +++ b/LightlessSync/LightlessSync.csproj @@ -27,7 +27,6 @@ - @@ -39,7 +38,6 @@ - all @@ -77,7 +75,23 @@ - + + + + + + + + lib\OtterTex.dll + true + + + + + + PreserveNewest + DirectXTexC.dll + diff --git a/LightlessSync/PlayerData/Data/FileReplacementDataComparer.cs b/LightlessSync/PlayerData/Data/FileReplacementDataComparer.cs index 7b52b49..5ba716b 100644 --- a/LightlessSync/PlayerData/Data/FileReplacementDataComparer.cs +++ b/LightlessSync/PlayerData/Data/FileReplacementDataComparer.cs @@ -1,4 +1,7 @@ -using LightlessSync.API.Data; +using LightlessSync.API.Data; +using System; +using System.Collections.Generic; +using System.Linq; namespace LightlessSync.PlayerData.Data; @@ -13,37 +16,42 @@ public class FileReplacementDataComparer : IEqualityComparer list1, HashSet list2) + private static bool ComparePathSets(IEnumerable first, IEnumerable second) { - if (list1.Count != list2.Count) - return false; - - for (int i = 0; i < list1.Count; i++) - { - if (!string.Equals(list1.ElementAt(i), list2.ElementAt(i), StringComparison.OrdinalIgnoreCase)) - return false; - } - - return true; + var left = new HashSet(first ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase); + var right = new HashSet(second ?? Enumerable.Empty(), StringComparer.OrdinalIgnoreCase); + return left.SetEquals(right); } - private static int GetOrderIndependentHashCode(IEnumerable source) where T : notnull + private static int GetSetHashCode(IEnumerable paths) { int hash = 0; - foreach (T element in source) + foreach (var element in paths ?? Enumerable.Empty()) { - hash = unchecked(hash + - EqualityComparer.Default.GetHashCode(element)); + hash = unchecked(hash + StringComparer.OrdinalIgnoreCase.GetHashCode(element)); } + return hash; } } \ No newline at end of file diff --git a/LightlessSync/PlayerData/Factories/FileDownloadManagerFactory.cs b/LightlessSync/PlayerData/Factories/FileDownloadManagerFactory.cs index 231ded3..81e3ecb 100644 --- a/LightlessSync/PlayerData/Factories/FileDownloadManagerFactory.cs +++ b/LightlessSync/PlayerData/Factories/FileDownloadManagerFactory.cs @@ -2,6 +2,7 @@ using LightlessSync.FileCache; using LightlessSync.LightlessConfiguration; using LightlessSync.Services; using LightlessSync.Services.Mediator; +using LightlessSync.Services.TextureCompression; using LightlessSync.WebAPI.Files; using Microsoft.Extensions.Logging; @@ -9,13 +10,15 @@ namespace LightlessSync.PlayerData.Factories; public class FileDownloadManagerFactory { - private readonly FileCacheManager _fileCacheManager; - private readonly FileCompactor _fileCompactor; - private readonly FileTransferOrchestrator _fileTransferOrchestrator; - private readonly PairProcessingLimiter _pairProcessingLimiter; private readonly ILoggerFactory _loggerFactory; private readonly LightlessMediator _lightlessMediator; + private readonly FileTransferOrchestrator _fileTransferOrchestrator; + private readonly FileCacheManager _fileCacheManager; + private readonly FileCompactor _fileCompactor; + private readonly PairProcessingLimiter _pairProcessingLimiter; private readonly LightlessConfigService _configService; + private readonly TextureDownscaleService _textureDownscaleService; + private readonly TextureMetadataHelper _textureMetadataHelper; public FileDownloadManagerFactory( ILoggerFactory loggerFactory, @@ -24,7 +27,9 @@ public class FileDownloadManagerFactory FileCacheManager fileCacheManager, FileCompactor fileCompactor, PairProcessingLimiter pairProcessingLimiter, - LightlessConfigService configService) + LightlessConfigService configService, + TextureDownscaleService textureDownscaleService, + TextureMetadataHelper textureMetadataHelper) { _loggerFactory = loggerFactory; _lightlessMediator = lightlessMediator; @@ -33,6 +38,8 @@ public class FileDownloadManagerFactory _fileCompactor = fileCompactor; _pairProcessingLimiter = pairProcessingLimiter; _configService = configService; + _textureDownscaleService = textureDownscaleService; + _textureMetadataHelper = textureMetadataHelper; } public FileDownloadManager Create() @@ -44,6 +51,8 @@ public class FileDownloadManagerFactory _fileCacheManager, _fileCompactor, _pairProcessingLimiter, - _configService); + _configService, + _textureDownscaleService, + _textureMetadataHelper); } } diff --git a/LightlessSync/PlayerData/Factories/GameObjectHandlerFactory.cs b/LightlessSync/PlayerData/Factories/GameObjectHandlerFactory.cs index 83a7ce6..4741b55 100644 --- a/LightlessSync/PlayerData/Factories/GameObjectHandlerFactory.cs +++ b/LightlessSync/PlayerData/Factories/GameObjectHandlerFactory.cs @@ -2,29 +2,40 @@ using LightlessSync.PlayerData.Handlers; using LightlessSync.Services; using LightlessSync.Services.Mediator; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace LightlessSync.PlayerData.Factories; public class GameObjectHandlerFactory { - private readonly DalamudUtilService _dalamudUtilService; + private readonly IServiceProvider _serviceProvider; private readonly ILoggerFactory _loggerFactory; private readonly LightlessMediator _lightlessMediator; private readonly PerformanceCollectorService _performanceCollectorService; - public GameObjectHandlerFactory(ILoggerFactory loggerFactory, PerformanceCollectorService performanceCollectorService, LightlessMediator lightlessMediator, - DalamudUtilService dalamudUtilService) + public GameObjectHandlerFactory( + ILoggerFactory loggerFactory, + PerformanceCollectorService performanceCollectorService, + LightlessMediator lightlessMediator, + IServiceProvider serviceProvider) { _loggerFactory = loggerFactory; _performanceCollectorService = performanceCollectorService; _lightlessMediator = lightlessMediator; - _dalamudUtilService = dalamudUtilService; + _serviceProvider = serviceProvider; } public async Task Create(ObjectKind objectKind, Func getAddressFunc, bool isWatched = false) { - return await _dalamudUtilService.RunOnFrameworkThread(() => new GameObjectHandler(_loggerFactory.CreateLogger(), - _performanceCollectorService, _lightlessMediator, _dalamudUtilService, objectKind, getAddressFunc, isWatched)).ConfigureAwait(false); + var dalamudUtilService = _serviceProvider.GetRequiredService(); + return await dalamudUtilService.RunOnFrameworkThread(() => new GameObjectHandler( + _loggerFactory.CreateLogger(), + _performanceCollectorService, + _lightlessMediator, + dalamudUtilService, + objectKind, + getAddressFunc, + isWatched)).ConfigureAwait(false); } } \ No newline at end of file diff --git a/LightlessSync/PlayerData/Factories/PairFactory.cs b/LightlessSync/PlayerData/Factories/PairFactory.cs index a9ee0ab..fd63f51 100644 --- a/LightlessSync/PlayerData/Factories/PairFactory.cs +++ b/LightlessSync/PlayerData/Factories/PairFactory.cs @@ -1,35 +1,86 @@ -using LightlessSync.API.Dto.User; +using System; +using System.Collections.Generic; +using System.Linq; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Dto.User; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; +using LightlessSync.UI.Models; using Microsoft.Extensions.Logging; +using LightlessSync.WebAPI; namespace LightlessSync.PlayerData.Factories; public class PairFactory { - private readonly PairHandlerFactory _cachedPlayerFactory; + private readonly PairLedger _pairLedger; private readonly ILoggerFactory _loggerFactory; private readonly LightlessMediator _lightlessMediator; - private readonly ServerConfigurationManager _serverConfigurationManager; + private readonly Lazy _serverConfigurationManager; + private readonly Lazy _apiController; - public PairFactory(ILoggerFactory loggerFactory, PairHandlerFactory cachedPlayerFactory, - LightlessMediator lightlessMediator, ServerConfigurationManager serverConfigurationManager) + public PairFactory( + ILoggerFactory loggerFactory, + PairLedger pairLedger, + LightlessMediator lightlessMediator, + Lazy serverConfigurationManager, + Lazy apiController) { _loggerFactory = loggerFactory; - _cachedPlayerFactory = cachedPlayerFactory; + _pairLedger = pairLedger; _lightlessMediator = lightlessMediator; _serverConfigurationManager = serverConfigurationManager; + _apiController = apiController; } public Pair Create(UserFullPairDto userPairDto) { - return new Pair(_loggerFactory.CreateLogger(), userPairDto, _cachedPlayerFactory, _lightlessMediator, _serverConfigurationManager); + return CreateInternal(userPairDto); } public Pair Create(UserPairDto userPairDto) { - return new Pair(_loggerFactory.CreateLogger(), new(userPairDto.User, userPairDto.IndividualPairStatus, [], userPairDto.OwnPermissions, userPairDto.OtherPermissions), - _cachedPlayerFactory, _lightlessMediator, _serverConfigurationManager); + var full = new UserFullPairDto( + userPairDto.User, + userPairDto.IndividualPairStatus, + new List(), + userPairDto.OwnPermissions, + userPairDto.OtherPermissions); + + return CreateInternal(full); } -} \ No newline at end of file + + public Pair? Create(PairDisplayEntry entry) + { + var dto = new UserFullPairDto( + entry.User, + entry.PairStatus ?? IndividualPairStatus.None, + entry.Groups.Select(g => g.Group.GID).Distinct(StringComparer.Ordinal).ToList(), + entry.SelfPermissions, + entry.OtherPermissions); + + return CreateInternal(dto); + } + + public Pair? Create(PairUniqueIdentifier ident) + { + if (!_pairLedger.TryGetEntry(ident, out var entry) || entry is null) + { + return null; + } + + return Create(entry); + } + + private Pair CreateInternal(UserFullPairDto dto) + { + return new Pair( + _loggerFactory.CreateLogger(), + dto, + _pairLedger, + _lightlessMediator, + _serverConfigurationManager.Value, + _apiController); + } +} diff --git a/LightlessSync/PlayerData/Factories/PairHandlerFactory.cs b/LightlessSync/PlayerData/Factories/PairHandlerFactory.cs deleted file mode 100644 index 9cb74da..0000000 --- a/LightlessSync/PlayerData/Factories/PairHandlerFactory.cs +++ /dev/null @@ -1,55 +0,0 @@ -using LightlessSync.FileCache; -using LightlessSync.Interop.Ipc; -using LightlessSync.PlayerData.Handlers; -using LightlessSync.PlayerData.Pairs; -using LightlessSync.Services; -using LightlessSync.Services.Mediator; -using LightlessSync.Services.ServerConfiguration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace LightlessSync.PlayerData.Factories; - -public class PairHandlerFactory -{ - private readonly DalamudUtilService _dalamudUtilService; - private readonly FileCacheManager _fileCacheManager; - private readonly FileDownloadManagerFactory _fileDownloadManagerFactory; - private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; - private readonly IHostApplicationLifetime _hostApplicationLifetime; - private readonly IpcManager _ipcManager; - private readonly ILoggerFactory _loggerFactory; - private readonly LightlessMediator _lightlessMediator; - private readonly PlayerPerformanceService _playerPerformanceService; - private readonly PairProcessingLimiter _pairProcessingLimiter; - private readonly ServerConfigurationManager _serverConfigManager; - private readonly PluginWarningNotificationService _pluginWarningNotificationManager; - - public PairHandlerFactory(ILoggerFactory loggerFactory, GameObjectHandlerFactory gameObjectHandlerFactory, IpcManager ipcManager, - FileDownloadManagerFactory fileDownloadManagerFactory, DalamudUtilService dalamudUtilService, - PluginWarningNotificationService pluginWarningNotificationManager, IHostApplicationLifetime hostApplicationLifetime, - FileCacheManager fileCacheManager, LightlessMediator lightlessMediator, PlayerPerformanceService playerPerformanceService, - PairProcessingLimiter pairProcessingLimiter, - ServerConfigurationManager serverConfigManager) - { - _loggerFactory = loggerFactory; - _gameObjectHandlerFactory = gameObjectHandlerFactory; - _ipcManager = ipcManager; - _fileDownloadManagerFactory = fileDownloadManagerFactory; - _dalamudUtilService = dalamudUtilService; - _pluginWarningNotificationManager = pluginWarningNotificationManager; - _hostApplicationLifetime = hostApplicationLifetime; - _fileCacheManager = fileCacheManager; - _lightlessMediator = lightlessMediator; - _playerPerformanceService = playerPerformanceService; - _pairProcessingLimiter = pairProcessingLimiter; - _serverConfigManager = serverConfigManager; - } - - public PairHandler Create(Pair pair) - { - return new PairHandler(_loggerFactory.CreateLogger(), pair, _gameObjectHandlerFactory, - _ipcManager, _fileDownloadManagerFactory.Create(), _pluginWarningNotificationManager, _dalamudUtilService, _hostApplicationLifetime, - _fileCacheManager, _lightlessMediator, _playerPerformanceService, _pairProcessingLimiter, _serverConfigManager); - } -} \ No newline at end of file diff --git a/LightlessSync/PlayerData/Handlers/PairHandler.cs b/LightlessSync/PlayerData/Handlers/PairHandler.cs deleted file mode 100644 index fb03bfb..0000000 --- a/LightlessSync/PlayerData/Handlers/PairHandler.cs +++ /dev/null @@ -1,775 +0,0 @@ -using LightlessSync.API.Data; -using LightlessSync.FileCache; -using LightlessSync.Interop.Ipc; -using LightlessSync.PlayerData.Factories; -using LightlessSync.PlayerData.Pairs; -using LightlessSync.Services; -using LightlessSync.Services.Events; -using LightlessSync.Services.Mediator; -using LightlessSync.Services.ServerConfiguration; -using LightlessSync.Utils; -using LightlessSync.WebAPI.Files; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; -using System.Diagnostics; -using ObjectKind = LightlessSync.API.Data.Enum.ObjectKind; - -namespace LightlessSync.PlayerData.Handlers; - -public sealed class PairHandler : DisposableMediatorSubscriberBase -{ - private sealed record CombatData(Guid ApplicationId, CharacterData CharacterData, bool Forced); - - private readonly DalamudUtilService _dalamudUtil; - private readonly FileDownloadManager _downloadManager; - private readonly FileCacheManager _fileDbManager; - private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; - private readonly IpcManager _ipcManager; - private readonly IHostApplicationLifetime _lifetime; - private readonly PlayerPerformanceService _playerPerformanceService; - private readonly PairProcessingLimiter _pairProcessingLimiter; - private readonly ServerConfigurationManager _serverConfigManager; - private readonly PluginWarningNotificationService _pluginWarningNotificationManager; - private CancellationTokenSource? _applicationCancellationTokenSource = new(); - private Guid _applicationId; - private Task? _applicationTask; - private CharacterData? _cachedData = null; - private GameObjectHandler? _charaHandler; - private readonly Dictionary _customizeIds = []; - private CombatData? _dataReceivedInDowntime; - private CancellationTokenSource? _downloadCancellationTokenSource = new(); - private bool _forceApplyMods = false; - private bool _isVisible; - private Guid _penumbraCollection; - private bool _redrawOnNextApplication = false; - - public PairHandler(ILogger logger, Pair pair, - GameObjectHandlerFactory gameObjectHandlerFactory, - IpcManager ipcManager, FileDownloadManager transferManager, - PluginWarningNotificationService pluginWarningNotificationManager, - DalamudUtilService dalamudUtil, IHostApplicationLifetime lifetime, - FileCacheManager fileDbManager, LightlessMediator mediator, - PlayerPerformanceService playerPerformanceService, - PairProcessingLimiter pairProcessingLimiter, - ServerConfigurationManager serverConfigManager) : base(logger, mediator) - { - Pair = pair; - _gameObjectHandlerFactory = gameObjectHandlerFactory; - _ipcManager = ipcManager; - _downloadManager = transferManager; - _pluginWarningNotificationManager = pluginWarningNotificationManager; - _dalamudUtil = dalamudUtil; - _lifetime = lifetime; - _fileDbManager = fileDbManager; - _playerPerformanceService = playerPerformanceService; - _pairProcessingLimiter = pairProcessingLimiter; - _serverConfigManager = serverConfigManager; - _penumbraCollection = _ipcManager.Penumbra.CreateTemporaryCollectionAsync(logger, Pair.UserData.UID).ConfigureAwait(false).GetAwaiter().GetResult(); - - Mediator.Subscribe(this, (_) => FrameworkUpdate()); - Mediator.Subscribe(this, (_) => - { - _downloadCancellationTokenSource?.CancelDispose(); - _charaHandler?.Invalidate(); - IsVisible = false; - }); - Mediator.Subscribe(this, (_) => - { - _penumbraCollection = _ipcManager.Penumbra.CreateTemporaryCollectionAsync(logger, Pair.UserData.UID).ConfigureAwait(false).GetAwaiter().GetResult(); - if (!IsVisible && _charaHandler != null) - { - PlayerName = string.Empty; - _charaHandler.Dispose(); - _charaHandler = null; - } - }); - Mediator.Subscribe(this, (msg) => - { - if (msg.GameObjectHandler == _charaHandler) - { - _redrawOnNextApplication = true; - } - }); - Mediator.Subscribe(this, (msg) => - { - EnableSync(); - }); - Mediator.Subscribe(this, _ => - { - DisableSync(); - }); - Mediator.Subscribe(this, (msg) => - { - EnableSync(); - }); - Mediator.Subscribe(this, _ => - { - DisableSync(); - }); - Mediator.Subscribe(this, _ => - { - DisableSync(); - }); - Mediator.Subscribe(this, (msg) => - { - EnableSync(); - - }); - - LastAppliedDataBytes = -1; - } - - public bool IsVisible - { - get => _isVisible; - private set - { - if (_isVisible != value) - { - _isVisible = value; - string text = "User Visibility Changed, now: " + (_isVisible ? "Is Visible" : "Is not Visible"); - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), - EventSeverity.Informational, text))); - Mediator.Publish(new RefreshUiMessage()); - Mediator.Publish(new VisibilityChange()); - } - } - } - - public long LastAppliedDataBytes { get; private set; } - public Pair Pair { get; private set; } - public nint PlayerCharacter => _charaHandler?.Address ?? nint.Zero; - public unsafe uint PlayerCharacterId => (_charaHandler?.Address ?? nint.Zero) == nint.Zero - ? uint.MaxValue - : ((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_charaHandler!.Address)->EntityId; - public string? PlayerName { get; private set; } - public string PlayerNameHash => Pair.Ident; - - public void ApplyCharacterData(Guid applicationBase, CharacterData characterData, bool forceApplyCustomization = false) - { - if (_dalamudUtil.IsInCombat) - { - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, - "Cannot apply character data: you are in combat, deferring application"))); - Logger.LogDebug("[BASE-{appBase}] Received data but player is in combat", applicationBase); - _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); - SetUploading(isUploading: false); - return; - } - - if (_dalamudUtil.IsPerforming) - { - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, - "Cannot apply character data: you are performing music, deferring application"))); - Logger.LogDebug("[BASE-{appBase}] Received data but player is performing", applicationBase); - _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); - SetUploading(isUploading: false); - return; - } - - if (_dalamudUtil.IsInInstance) - { - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, - "Cannot apply character data: you are in an instance, deferring application"))); - Logger.LogDebug("[BASE-{appBase}] Received data but player is in instance", applicationBase); - _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); - SetUploading(isUploading: false); - return; - } - - if (_charaHandler == null || (PlayerCharacter == IntPtr.Zero)) - { - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, - "Cannot apply character data: Receiving Player is in an invalid state, deferring application"))); - Logger.LogDebug("[BASE-{appBase}] Received data but player was in invalid state, charaHandlerIsNull: {charaIsNull}, playerPointerIsNull: {ptrIsNull}", - applicationBase, _charaHandler == null, PlayerCharacter == IntPtr.Zero); - var hasDiffMods = characterData.CheckUpdatedData(applicationBase, _cachedData, Logger, - this, forceApplyCustomization, forceApplyMods: false) - .Any(p => p.Value.Contains(PlayerChanges.ModManip) || p.Value.Contains(PlayerChanges.ModFiles)); - _forceApplyMods = hasDiffMods || _forceApplyMods || (PlayerCharacter == IntPtr.Zero && _cachedData == null); - _cachedData = characterData; - Logger.LogDebug("[BASE-{appBase}] Setting data: {hash}, forceApplyMods: {force}", applicationBase, _cachedData.DataHash.Value, _forceApplyMods); - return; - } - - SetUploading(isUploading: false); - - Logger.LogDebug("[BASE-{appbase}] Applying data for {player}, forceApplyCustomization: {forced}, forceApplyMods: {forceMods}", applicationBase, this, forceApplyCustomization, _forceApplyMods); - Logger.LogDebug("[BASE-{appbase}] Hash for data is {newHash}, current cache hash is {oldHash}", applicationBase, characterData.DataHash.Value, _cachedData?.DataHash.Value ?? "NODATA"); - - if (string.Equals(characterData.DataHash.Value, _cachedData?.DataHash.Value ?? string.Empty, StringComparison.Ordinal) && !forceApplyCustomization) return; - - if (_dalamudUtil.IsInCutscene || _dalamudUtil.IsInGpose || !_ipcManager.Penumbra.APIAvailable || !_ipcManager.Glamourer.APIAvailable) - { - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Warning, - "Cannot apply character data: you are in GPose, a Cutscene or Penumbra/Glamourer is not available"))); - Logger.LogInformation("[BASE-{appbase}] Application of data for {player} while in cutscene/gpose or Penumbra/Glamourer unavailable, returning", applicationBase, this); - return; - } - - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Informational, - "Applying Character Data"))); - - _forceApplyMods |= forceApplyCustomization; - - var charaDataToUpdate = characterData.CheckUpdatedData(applicationBase, _cachedData?.DeepClone() ?? new(), Logger, this, forceApplyCustomization, _forceApplyMods); - - if (_charaHandler != null && _forceApplyMods) - { - _forceApplyMods = false; - } - - if (_redrawOnNextApplication && charaDataToUpdate.TryGetValue(ObjectKind.Player, out var player)) - { - player.Add(PlayerChanges.ForcedRedraw); - _redrawOnNextApplication = false; - } - - if (charaDataToUpdate.TryGetValue(ObjectKind.Player, out var playerChanges)) - { - _pluginWarningNotificationManager.NotifyForMissingPlugins(Pair.UserData, PlayerName!, playerChanges); - } - - Logger.LogDebug("[BASE-{appbase}] Downloading and applying character for {name}", applicationBase, this); - - DownloadAndApplyCharacter(applicationBase, characterData.DeepClone(), charaDataToUpdate); - } - - public override string ToString() - { - return Pair == null - ? base.ToString() ?? string.Empty - : Pair.UserData.AliasOrUID + ":" + PlayerName + ":" + (PlayerCharacter != nint.Zero ? "HasChar" : "NoChar"); - } - - internal void SetUploading(bool isUploading = true) - { - Logger.LogTrace("Setting {this} uploading {uploading}", this, isUploading); - if (_charaHandler != null) - { - Mediator.Publish(new PlayerUploadingMessage(_charaHandler, isUploading)); - } - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - SetUploading(isUploading: false); - var name = PlayerName; - Logger.LogDebug("Disposing {name} ({user})", name, Pair); - try - { - Guid applicationId = Guid.NewGuid(); - _applicationCancellationTokenSource?.CancelDispose(); - _applicationCancellationTokenSource = null; - _downloadCancellationTokenSource?.CancelDispose(); - _downloadCancellationTokenSource = null; - _downloadManager.Dispose(); - _charaHandler?.Dispose(); - _charaHandler = null; - - if (!string.IsNullOrEmpty(name)) - { - Mediator.Publish(new EventMessage(new Event(name, Pair.UserData, nameof(PairHandler), EventSeverity.Informational, "Disposing User"))); - } - - if (_lifetime.ApplicationStopping.IsCancellationRequested) return; - - if (_dalamudUtil is { IsZoning: false, IsInCutscene: false } && !string.IsNullOrEmpty(name)) - { - Logger.LogTrace("[{applicationId}] Restoring state for {name} ({OnlineUser})", applicationId, name, Pair.UserPair); - Logger.LogDebug("[{applicationId}] Removing Temp Collection for {name} ({user})", applicationId, name, Pair.UserPair); - _ipcManager.Penumbra.RemoveTemporaryCollectionAsync(Logger, applicationId, _penumbraCollection).GetAwaiter().GetResult(); - if (!IsVisible) - { - Logger.LogDebug("[{applicationId}] Restoring Glamourer for {name} ({user})", applicationId, name, Pair.UserPair); - _ipcManager.Glamourer.RevertByNameAsync(Logger, name, applicationId).GetAwaiter().GetResult(); - } - else - { - using var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromSeconds(60)); - - Logger.LogInformation("[{applicationId}] CachedData is null {isNull}, contains things: {contains}", applicationId, _cachedData == null, _cachedData?.FileReplacements.Any() ?? false); - - foreach (KeyValuePair> item in _cachedData?.FileReplacements ?? []) - { - try - { - RevertCustomizationDataAsync(item.Key, name, applicationId, cts.Token).GetAwaiter().GetResult(); - } - catch (InvalidOperationException ex) - { - Logger.LogWarning(ex, "Failed disposing player (not present anymore?)"); - break; - } - } - } - } - } - catch (Exception ex) - { - Logger.LogWarning(ex, "Error on disposal of {name}", name); - } - finally - { - PlayerName = null; - _cachedData = null; - Logger.LogDebug("Disposing {name} complete", name); - } - } - - private async Task ApplyCustomizationDataAsync(Guid applicationId, KeyValuePair> changes, CharacterData charaData, CancellationToken token) - { - if (PlayerCharacter == nint.Zero) return; - var ptr = PlayerCharacter; - - var handler = changes.Key switch - { - ObjectKind.Player => _charaHandler!, - ObjectKind.Companion => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetCompanionPtr(ptr), isWatched: false).ConfigureAwait(false), - ObjectKind.MinionOrMount => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetMinionOrMountPtr(ptr), isWatched: false).ConfigureAwait(false), - ObjectKind.Pet => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetPetPtr(ptr), isWatched: false).ConfigureAwait(false), - _ => throw new NotSupportedException("ObjectKind not supported: " + changes.Key) - }; - - try - { - if (handler.Address == nint.Zero) - { - return; - } - - Logger.LogDebug("[{applicationId}] Applying Customization Data for {handler}", applicationId, handler); - await _dalamudUtil.WaitWhileCharacterIsDrawing(Logger, handler, applicationId, 30000, token).ConfigureAwait(false); - token.ThrowIfCancellationRequested(); - foreach (var change in changes.Value.OrderBy(p => (int)p)) - { - Logger.LogDebug("[{applicationId}] Processing {change} for {handler}", applicationId, change, handler); - switch (change) - { - case PlayerChanges.Customize: - if (charaData.CustomizePlusData.TryGetValue(changes.Key, out var customizePlusData)) - { - _customizeIds[changes.Key] = await _ipcManager.CustomizePlus.SetBodyScaleAsync(handler.Address, customizePlusData).ConfigureAwait(false); - } - else if (_customizeIds.TryGetValue(changes.Key, out var customizeId)) - { - await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); - _customizeIds.Remove(changes.Key); - } - break; - - case PlayerChanges.Heels: - await _ipcManager.Heels.SetOffsetForPlayerAsync(handler.Address, charaData.HeelsData).ConfigureAwait(false); - break; - - case PlayerChanges.Honorific: - await _ipcManager.Honorific.SetTitleAsync(handler.Address, charaData.HonorificData).ConfigureAwait(false); - break; - - case PlayerChanges.Glamourer: - if (charaData.GlamourerData.TryGetValue(changes.Key, out var glamourerData)) - { - await _ipcManager.Glamourer.ApplyAllAsync(Logger, handler, glamourerData, applicationId, token).ConfigureAwait(false); - } - break; - - case PlayerChanges.Moodles: - await _ipcManager.Moodles.SetStatusAsync(handler.Address, charaData.MoodlesData).ConfigureAwait(false); - break; - - case PlayerChanges.PetNames: - await _ipcManager.PetNames.SetPlayerData(handler.Address, charaData.PetNamesData).ConfigureAwait(false); - break; - - case PlayerChanges.ForcedRedraw: - await _ipcManager.Penumbra.RedrawAsync(Logger, handler, applicationId, token).ConfigureAwait(false); - break; - - default: - break; - } - token.ThrowIfCancellationRequested(); - } - } - finally - { - if (handler != _charaHandler) handler.Dispose(); - } - } - - private void DownloadAndApplyCharacter(Guid applicationBase, CharacterData charaData, Dictionary> updatedData) - { - if (!updatedData.Any()) - { - Logger.LogDebug("[BASE-{appBase}] Nothing to update for {obj}", applicationBase, this); - return; - } - - var updateModdedPaths = updatedData.Values.Any(v => v.Any(p => p == PlayerChanges.ModFiles)); - var updateManip = updatedData.Values.Any(v => v.Any(p => p == PlayerChanges.ModManip)); - - _downloadCancellationTokenSource = _downloadCancellationTokenSource?.CancelRecreate() ?? new CancellationTokenSource(); - var downloadToken = _downloadCancellationTokenSource.Token; - - _ = DownloadAndApplyCharacterAsync(applicationBase, charaData, updatedData, updateModdedPaths, updateManip, downloadToken).ConfigureAwait(false); - } - - private Task? _pairDownloadTask; - - private async Task DownloadAndApplyCharacterAsync(Guid applicationBase, CharacterData charaData, Dictionary> updatedData, - bool updateModdedPaths, bool updateManip, CancellationToken downloadToken) - { - await using var concurrencyLease = await _pairProcessingLimiter.AcquireAsync(downloadToken).ConfigureAwait(false); - Dictionary<(string GamePath, string? Hash), string> moddedPaths = []; - - if (updateModdedPaths) - { - int attempts = 0; - List toDownloadReplacements = TryCalculateModdedDictionary(applicationBase, charaData, out moddedPaths, downloadToken); - - while (toDownloadReplacements.Count > 0 && attempts++ <= 10 && !downloadToken.IsCancellationRequested) - { - if (_pairDownloadTask != null && !_pairDownloadTask.IsCompleted) - { - Logger.LogDebug("[BASE-{appBase}] Finishing prior running download task for player {name}, {kind}", applicationBase, PlayerName, updatedData); - await _pairDownloadTask.ConfigureAwait(false); - } - - Logger.LogDebug("[BASE-{appBase}] Downloading missing files for player {name}, {kind}", applicationBase, PlayerName, updatedData); - - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Informational, - $"Starting download for {toDownloadReplacements.Count} files"))); - var toDownloadFiles = await _downloadManager.InitiateDownloadList(_charaHandler!, toDownloadReplacements, downloadToken).ConfigureAwait(false); - - if (!_playerPerformanceService.ComputeAndAutoPauseOnVRAMUsageThresholds(this, charaData, toDownloadFiles)) - { - _downloadManager.ClearDownload(); - return; - } - - _pairDownloadTask = Task.Run(async () => await _downloadManager.DownloadFiles(_charaHandler!, toDownloadReplacements, downloadToken).ConfigureAwait(false)); - - await _pairDownloadTask.ConfigureAwait(false); - - if (downloadToken.IsCancellationRequested) - { - Logger.LogTrace("[BASE-{appBase}] Detected cancellation", applicationBase); - return; - } - - toDownloadReplacements = TryCalculateModdedDictionary(applicationBase, charaData, out moddedPaths, downloadToken); - - if (toDownloadReplacements.TrueForAll(c => _downloadManager.ForbiddenTransfers.Exists(f => string.Equals(f.Hash, c.Hash, StringComparison.Ordinal)))) - { - break; - } - - await Task.Delay(TimeSpan.FromSeconds(2), downloadToken).ConfigureAwait(false); - } - - if (!await _playerPerformanceService.CheckBothThresholds(this, charaData).ConfigureAwait(false)) - return; - } - - downloadToken.ThrowIfCancellationRequested(); - - var appToken = _applicationCancellationTokenSource?.Token; - while ((!_applicationTask?.IsCompleted ?? false) - && !downloadToken.IsCancellationRequested - && (!appToken?.IsCancellationRequested ?? false)) - { - // block until current application is done - Logger.LogDebug("[BASE-{appBase}] Waiting for current data application (Id: {id}) for player ({handler}) to finish", applicationBase, _applicationId, PlayerName); - await Task.Delay(250).ConfigureAwait(false); - } - - if (downloadToken.IsCancellationRequested || (appToken?.IsCancellationRequested ?? false)) return; - - _applicationCancellationTokenSource = _applicationCancellationTokenSource.CancelRecreate() ?? new CancellationTokenSource(); - var token = _applicationCancellationTokenSource.Token; - - _applicationTask = ApplyCharacterDataAsync(applicationBase, charaData, updatedData, updateModdedPaths, updateManip, moddedPaths, token); - } - - private async Task ApplyCharacterDataAsync(Guid applicationBase, CharacterData charaData, Dictionary> updatedData, bool updateModdedPaths, bool updateManip, - Dictionary<(string GamePath, string? Hash), string> moddedPaths, CancellationToken token) - { - try - { - _applicationId = Guid.NewGuid(); - Logger.LogDebug("[BASE-{applicationId}] Starting application task for {this}: {appId}", applicationBase, this, _applicationId); - - Logger.LogDebug("[{applicationId}] Waiting for initial draw for for {handler}", _applicationId, _charaHandler); - await _dalamudUtil.WaitWhileCharacterIsDrawing(Logger, _charaHandler!, _applicationId, 30000, token).ConfigureAwait(false); - - token.ThrowIfCancellationRequested(); - - if (updateModdedPaths) - { - // ensure collection is set - var objIndex = await _dalamudUtil.RunOnFrameworkThread(() => _charaHandler!.GetGameObject()!.ObjectIndex).ConfigureAwait(false); - await _ipcManager.Penumbra.AssignTemporaryCollectionAsync(Logger, _penumbraCollection, objIndex).ConfigureAwait(false); - - await _ipcManager.Penumbra.SetTemporaryModsAsync(Logger, _applicationId, _penumbraCollection, - moddedPaths.ToDictionary(k => k.Key.GamePath, k => k.Value, StringComparer.Ordinal)).ConfigureAwait(false); - LastAppliedDataBytes = -1; - foreach (var path in moddedPaths.Values.Distinct(StringComparer.OrdinalIgnoreCase).Select(v => new FileInfo(v)).Where(p => p.Exists)) - { - if (LastAppliedDataBytes == -1) LastAppliedDataBytes = 0; - - LastAppliedDataBytes += path.Length; - } - } - - if (updateManip) - { - await _ipcManager.Penumbra.SetManipulationDataAsync(Logger, _applicationId, _penumbraCollection, charaData.ManipulationData).ConfigureAwait(false); - } - - token.ThrowIfCancellationRequested(); - - foreach (var kind in updatedData) - { - await ApplyCustomizationDataAsync(_applicationId, kind, charaData, token).ConfigureAwait(false); - token.ThrowIfCancellationRequested(); - } - - _cachedData = charaData; - - Logger.LogDebug("[{applicationId}] Application finished", _applicationId); - } - catch (Exception ex) - { - if (ex is AggregateException aggr && aggr.InnerExceptions.Any(e => e is ArgumentNullException)) - { - IsVisible = false; - _forceApplyMods = true; - _cachedData = charaData; - Logger.LogDebug("[{applicationId}] Cancelled, player turned null during application", _applicationId); - } - else - { - Logger.LogWarning(ex, "[{applicationId}] Cancelled", _applicationId); - } - } - } - - private void FrameworkUpdate() - { - if (string.IsNullOrEmpty(PlayerName)) - { - var pc = _dalamudUtil.FindPlayerByNameHash(Pair.Ident); - if (pc == default((string, nint))) return; - Logger.LogDebug("One-Time Initializing {this}", this); - Initialize(pc.Name); - Logger.LogDebug("One-Time Initialized {this}", this); - Mediator.Publish(new EventMessage(new Event(PlayerName, Pair.UserData, nameof(PairHandler), EventSeverity.Informational, - $"Initializing User For Character {pc.Name}"))); - } - - if (_charaHandler?.Address != nint.Zero && !IsVisible) - { - Guid appData = Guid.NewGuid(); - IsVisible = true; - if (_cachedData != null) - { - Logger.LogTrace("[BASE-{appBase}] {this} visibility changed, now: {visi}, cached data exists", appData, this, IsVisible); - - _ = Task.Run(() => - { - ApplyCharacterData(appData, _cachedData!, forceApplyCustomization: true); - }); - } - else - { - Logger.LogTrace("{this} visibility changed, now: {visi}, no cached data exists", this, IsVisible); - } - } - else if (_charaHandler?.Address == nint.Zero && IsVisible) - { - IsVisible = false; - _charaHandler.Invalidate(); - _downloadCancellationTokenSource?.CancelDispose(); - _downloadCancellationTokenSource = null; - Logger.LogTrace("{this} visibility changed, now: {visi}", this, IsVisible); - } - } - - private void Initialize(string name) - { - PlayerName = name; - _charaHandler = _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(Pair.Ident), isWatched: false).GetAwaiter().GetResult(); - - _serverConfigManager.AutoPopulateNoteForUid(Pair.UserData.UID, name); - - Mediator.Subscribe(this, async (_) => - { - if (string.IsNullOrEmpty(_cachedData?.HonorificData)) return; - Logger.LogTrace("Reapplying Honorific data for {this}", this); - await _ipcManager.Honorific.SetTitleAsync(PlayerCharacter, _cachedData.HonorificData).ConfigureAwait(false); - }); - - Mediator.Subscribe(this, async (_) => - { - if (string.IsNullOrEmpty(_cachedData?.PetNamesData)) return; - Logger.LogTrace("Reapplying Pet Names data for {this}", this); - await _ipcManager.PetNames.SetPlayerData(PlayerCharacter, _cachedData.PetNamesData).ConfigureAwait(false); - }); - - _ipcManager.Penumbra.AssignTemporaryCollectionAsync(Logger, _penumbraCollection, _charaHandler.GetGameObject()!.ObjectIndex).GetAwaiter().GetResult(); - } - - private async Task RevertCustomizationDataAsync(ObjectKind objectKind, string name, Guid applicationId, CancellationToken cancelToken) - { - nint address = _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(Pair.Ident); - if (address == nint.Zero) return; - - Logger.LogDebug("[{applicationId}] Reverting all Customization for {alias}/{name} {objectKind}", applicationId, Pair.UserData.AliasOrUID, name, objectKind); - - if (_customizeIds.TryGetValue(objectKind, out var customizeId)) - { - _customizeIds.Remove(objectKind); - } - - if (objectKind == ObjectKind.Player) - { - using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => address, isWatched: false).ConfigureAwait(false); - tempHandler.CompareNameAndThrow(name); - Logger.LogDebug("[{applicationId}] Restoring Customization and Equipment for {alias}/{name}", applicationId, Pair.UserData.AliasOrUID, name); - await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - tempHandler.CompareNameAndThrow(name); - Logger.LogDebug("[{applicationId}] Restoring Heels for {alias}/{name}", applicationId, Pair.UserData.AliasOrUID, name); - await _ipcManager.Heels.RestoreOffsetForPlayerAsync(address).ConfigureAwait(false); - tempHandler.CompareNameAndThrow(name); - Logger.LogDebug("[{applicationId}] Restoring C+ for {alias}/{name}", applicationId, Pair.UserData.AliasOrUID, name); - await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); - tempHandler.CompareNameAndThrow(name); - Logger.LogDebug("[{applicationId}] Restoring Honorific for {alias}/{name}", applicationId, Pair.UserData.AliasOrUID, name); - await _ipcManager.Honorific.ClearTitleAsync(address).ConfigureAwait(false); - Logger.LogDebug("[{applicationId}] Restoring Moodles for {alias}/{name}", applicationId, Pair.UserData.AliasOrUID, name); - await _ipcManager.Moodles.RevertStatusAsync(address).ConfigureAwait(false); - Logger.LogDebug("[{applicationId}] Restoring Pet Nicknames for {alias}/{name}", applicationId, Pair.UserData.AliasOrUID, name); - await _ipcManager.PetNames.ClearPlayerData(address).ConfigureAwait(false); - } - else if (objectKind == ObjectKind.MinionOrMount) - { - var minionOrMount = await _dalamudUtil.GetMinionOrMountAsync(address).ConfigureAwait(false); - if (minionOrMount != nint.Zero) - { - await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); - using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => minionOrMount, isWatched: false).ConfigureAwait(false); - await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - await _ipcManager.Penumbra.RedrawAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - } - } - else if (objectKind == ObjectKind.Pet) - { - var pet = await _dalamudUtil.GetPetAsync(address).ConfigureAwait(false); - if (pet != nint.Zero) - { - await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); - using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => pet, isWatched: false).ConfigureAwait(false); - await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - await _ipcManager.Penumbra.RedrawAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - } - } - else if (objectKind == ObjectKind.Companion) - { - var companion = await _dalamudUtil.GetCompanionAsync(address).ConfigureAwait(false); - if (companion != nint.Zero) - { - await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); - using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => companion, isWatched: false).ConfigureAwait(false); - await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - await _ipcManager.Penumbra.RedrawAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); - } - } - } - - private List TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary<(string GamePath, string? Hash), string> moddedDictionary, CancellationToken token) - { - Stopwatch st = Stopwatch.StartNew(); - ConcurrentBag missingFiles = []; - moddedDictionary = []; - ConcurrentDictionary<(string GamePath, string? Hash), string> outputDict = new(); - bool hasMigrationChanges = false; - - try - { - var replacementList = charaData.FileReplacements.SelectMany(k => k.Value.Where(v => string.IsNullOrEmpty(v.FileSwapPath))).ToList(); - Parallel.ForEach(replacementList, new ParallelOptions() - { - CancellationToken = token, - MaxDegreeOfParallelism = 4 - }, - (item) => - { - token.ThrowIfCancellationRequested(); - var fileCache = _fileDbManager.GetFileCacheByHash(item.Hash); - if (fileCache != null) - { - if (string.IsNullOrEmpty(new FileInfo(fileCache.ResolvedFilepath).Extension)) - { - hasMigrationChanges = true; - fileCache = _fileDbManager.MigrateFileHashToExtension(fileCache, item.GamePaths[0].Split(".")[^1]); - } - - foreach (var gamePath in item.GamePaths) - { - outputDict[(gamePath, item.Hash)] = fileCache.ResolvedFilepath; - } - } - else - { - Logger.LogTrace("Missing file: {hash}", item.Hash); - missingFiles.Add(item); - } - }); - - moddedDictionary = outputDict.ToDictionary(k => k.Key, k => k.Value); - - foreach (var item in charaData.FileReplacements.SelectMany(k => k.Value.Where(v => !string.IsNullOrEmpty(v.FileSwapPath))).ToList()) - { - foreach (var gamePath in item.GamePaths) - { - Logger.LogTrace("[BASE-{appBase}] Adding file swap for {path}: {fileSwap}", applicationBase, gamePath, item.FileSwapPath); - moddedDictionary[(gamePath, null)] = item.FileSwapPath; - } - } - } - catch (OperationCanceledException) - { - Logger.LogTrace("[BASE-{appBase}] Modded path calculation cancelled", applicationBase); - throw; - } - catch (Exception ex) - { - Logger.LogError(ex, "[BASE-{appBase}] Something went wrong during calculation replacements", applicationBase); - } - if (hasMigrationChanges) _fileDbManager.WriteOutFullCsv(); - st.Stop(); - Logger.LogDebug("[BASE-{appBase}] ModdedPaths calculated in {time}ms, missing files: {count}, total files: {total}", applicationBase, st.ElapsedMilliseconds, missingFiles.Count, moddedDictionary.Keys.Count); - return [.. missingFiles]; - } - - private void DisableSync() - { - _dataReceivedInDowntime = null; - _downloadCancellationTokenSource = _downloadCancellationTokenSource?.CancelRecreate(); - _applicationCancellationTokenSource = _applicationCancellationTokenSource?.CancelRecreate(); - } - - private void EnableSync() - { - if (IsVisible && _dataReceivedInDowntime != null) - { - ApplyCharacterData(_dataReceivedInDowntime.ApplicationId, - _dataReceivedInDowntime.CharacterData, _dataReceivedInDowntime.Forced); - _dataReceivedInDowntime = null; - } - } -} diff --git a/LightlessSync/PlayerData/Pairs/IPairPerformanceSubject.cs b/LightlessSync/PlayerData/Pairs/IPairPerformanceSubject.cs new file mode 100644 index 0000000..a11893b --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/IPairPerformanceSubject.cs @@ -0,0 +1,16 @@ +using LightlessSync.API.Data; + +namespace LightlessSync.PlayerData.Pairs; + +public interface IPairPerformanceSubject +{ + string Ident { get; } + string PlayerName { get; } + UserData UserData { get; } + bool IsPaused { get; } + bool IsDirectlyPaired { get; } + bool HasStickyPermissions { get; } + long LastAppliedApproximateVRAMBytes { get; set; } + long LastAppliedApproximateEffectiveVRAMBytes { get; set; } + long LastAppliedDataTris { get; set; } +} diff --git a/LightlessSync/PlayerData/Pairs/Pair.cs b/LightlessSync/PlayerData/Pairs/Pair.cs index d4e2950..7709b06 100644 --- a/LightlessSync/PlayerData/Pairs/Pair.cs +++ b/LightlessSync/PlayerData/Pairs/Pair.cs @@ -1,103 +1,133 @@ -using Dalamud.Game.Gui.ContextMenu; +using System; +using System.Linq; +using Dalamud.Game.Gui.ContextMenu; using Dalamud.Game.Text.SeStringHandling; using LightlessSync.API.Data; using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.User; -using LightlessSync.PlayerData.Factories; -using LightlessSync.PlayerData.Handlers; +using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; -using LightlessSync.Utils; using Microsoft.Extensions.Logging; +using LightlessSync.WebAPI; namespace LightlessSync.PlayerData.Pairs; public class Pair { - private readonly PairHandlerFactory _cachedPlayerFactory; - private readonly SemaphoreSlim _creationSemaphore = new(1); + private readonly PairLedger _pairLedger; private readonly ILogger _logger; private readonly LightlessMediator _mediator; private readonly ServerConfigurationManager _serverConfigurationManager; - private CancellationTokenSource _applicationCts = new(); - private OnlineUserIdentDto? _onlineUserIdentDto = null; + private readonly Lazy _apiController; - public Pair(ILogger logger, UserFullPairDto userPair, PairHandlerFactory cachedPlayerFactory, - LightlessMediator mediator, ServerConfigurationManager serverConfigurationManager) + public Pair( + ILogger logger, + UserFullPairDto userPair, + PairLedger pairLedger, + LightlessMediator mediator, + ServerConfigurationManager serverConfigurationManager, + Lazy apiController) { _logger = logger; UserPair = userPair; - _cachedPlayerFactory = cachedPlayerFactory; + _pairLedger = pairLedger; _mediator = mediator; _serverConfigurationManager = serverConfigurationManager; + _apiController = apiController; } - public bool HasCachedPlayer => CachedPlayer != null && !string.IsNullOrEmpty(CachedPlayer.PlayerName) && _onlineUserIdentDto != null; + private PairUniqueIdentifier PairIdent => UniqueIdent; + + private IPairHandlerAdapter? TryGetHandler() + { + return _pairLedger.GetHandler(PairIdent); + } + + private PairConnection? TryGetConnection() + { + return _pairLedger.TryGetEntry(PairIdent, out var entry) && entry is not null + ? entry.Connection + : null; + } + + public bool HasCachedPlayer => TryGetHandler() is not null; public IndividualPairStatus IndividualPairStatus => UserPair.IndividualPairStatus; public bool IsDirectlyPaired => IndividualPairStatus != IndividualPairStatus.None; public bool IsOneSidedPair => IndividualPairStatus == IndividualPairStatus.OneSided; - public bool IsOnline => CachedPlayer != null; + + public bool IsOnline => TryGetConnection()?.IsOnline ?? false; public bool IsPaired => IndividualPairStatus == IndividualPairStatus.Bidirectional || UserPair.Groups.Any(); public bool IsPaused => UserPair.OwnPermissions.IsPaused(); - public bool IsVisible => CachedPlayer?.IsVisible ?? false; - public CharacterData? LastReceivedCharacterData { get; set; } - public string? PlayerName => CachedPlayer?.PlayerName ?? string.Empty; - public long LastAppliedDataBytes => CachedPlayer?.LastAppliedDataBytes ?? -1; - public long LastAppliedDataTris { get; set; } = -1; - public long LastAppliedApproximateVRAMBytes { get; set; } = -1; - public string Ident => _onlineUserIdentDto?.Ident ?? string.Empty; - public uint PlayerCharacterId => CachedPlayer?.PlayerCharacterId ?? uint.MaxValue; + public bool IsVisible => _pairLedger.IsPairVisible(PairIdent); + public CharacterData? LastReceivedCharacterData => TryGetHandler()?.LastReceivedCharacterData; + public string? PlayerName => TryGetHandler()?.PlayerName ?? UserPair.User.AliasOrUID; + public long LastAppliedDataBytes => TryGetHandler()?.LastAppliedDataBytes ?? -1; + public long LastAppliedDataTris => TryGetHandler()?.LastAppliedDataTris ?? -1; + public long LastAppliedApproximateVRAMBytes => TryGetHandler()?.LastAppliedApproximateVRAMBytes ?? -1; + public long LastAppliedApproximateEffectiveVRAMBytes => TryGetHandler()?.LastAppliedApproximateEffectiveVRAMBytes ?? -1; + public string Ident => TryGetHandler()?.Ident ?? TryGetConnection()?.Ident ?? string.Empty; + public uint PlayerCharacterId => TryGetHandler()?.PlayerCharacterId ?? uint.MaxValue; + public PairUniqueIdentifier UniqueIdent => new(UserData.UID); public UserData UserData => UserPair.User; public UserFullPairDto UserPair { get; set; } - private PairHandler? CachedPlayer { get; set; } public void AddContextMenu(IMenuOpenedArgs args) { - if (CachedPlayer == null || (args.Target is not MenuTargetDefault target) || target.TargetObjectId != CachedPlayer.PlayerCharacterId || IsPaused) return; + var handler = TryGetHandler(); + if (handler is null) + { + return; + } - SeStringBuilder seStringBuilder = new(); - SeStringBuilder seStringBuilder2 = new(); - SeStringBuilder seStringBuilder3 = new(); - SeStringBuilder seStringBuilder4 = new(); - var openProfileSeString = seStringBuilder.AddText("Open Profile").Build(); - var reapplyDataSeString = seStringBuilder2.AddText("Reapply last data").Build(); - var cyclePauseState = seStringBuilder3.AddText("Cycle pause state").Build(); - var changePermissions = seStringBuilder4.AddText("Change Permissions").Build(); - args.AddMenuItem(new MenuItem() + if (args.Target is not MenuTargetDefault target || target.TargetObjectId != handler.PlayerCharacterId || IsPaused) + { + return; + } + + var openProfileSeString = new SeStringBuilder().AddText("Open Profile").Build(); + var reapplyDataSeString = new SeStringBuilder().AddText("Reapply last data").Build(); + var cyclePauseState = new SeStringBuilder().AddText("Cycle pause state").Build(); + var changePermissions = new SeStringBuilder().AddText("Change Permissions").Build(); + + args.AddMenuItem(new MenuItem { Name = openProfileSeString, - OnClicked = (a) => _mediator.Publish(new ProfileOpenStandaloneMessage(this)), + OnClicked = _ => _mediator.Publish(new ProfileOpenStandaloneMessage(this)), UseDefaultPrefix = false, PrefixChar = 'L', PrefixColor = 708 }); - args.AddMenuItem(new MenuItem() + args.AddMenuItem(new MenuItem { Name = reapplyDataSeString, - OnClicked = (a) => ApplyLastReceivedData(forced: true), + OnClicked = _ => ApplyLastReceivedData(forced: true), UseDefaultPrefix = false, PrefixChar = 'L', PrefixColor = 708 }); - args.AddMenuItem(new MenuItem() + args.AddMenuItem(new MenuItem { Name = changePermissions, - OnClicked = (a) => _mediator.Publish(new OpenPermissionWindow(this)), + OnClicked = _ => _mediator.Publish(new OpenPermissionWindow(this)), UseDefaultPrefix = false, PrefixChar = 'L', PrefixColor = 708 }); - args.AddMenuItem(new MenuItem() + args.AddMenuItem(new MenuItem { Name = cyclePauseState, - OnClicked = (a) => _mediator.Publish(new CyclePauseMessage(UserData)), + OnClicked = _ => + { + TriggerCyclePause(); + }, UseDefaultPrefix = false, PrefixChar = 'L', PrefixColor = 708 @@ -106,68 +136,38 @@ public class Pair public void ApplyData(OnlineUserCharaDataDto data) { - _applicationCts = _applicationCts.CancelRecreate(); - LastReceivedCharacterData = data.CharaData; + _logger.LogTrace("Character data received for {Uid}; handler will process via registry.", UserData.UID); + } - if (CachedPlayer == null) - { - _logger.LogDebug("Received Data for {uid} but CachedPlayer does not exist, waiting", data.User.UID); - _ = Task.Run(async () => - { - using var timeoutCts = new CancellationTokenSource(); - timeoutCts.CancelAfter(TimeSpan.FromSeconds(120)); - var appToken = _applicationCts.Token; - using var combined = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, appToken); - while (CachedPlayer == null && !combined.Token.IsCancellationRequested) - { - await Task.Delay(250, combined.Token).ConfigureAwait(false); - } - - if (!combined.IsCancellationRequested) - { - _logger.LogDebug("Applying delayed data for {uid}", data.User.UID); - ApplyLastReceivedData(); - } - }); - return; - } - - ApplyLastReceivedData(); + private void TriggerCyclePause() + { + _ = _apiController.Value.CyclePauseAsync(this); } public void ApplyLastReceivedData(bool forced = false) { - if (CachedPlayer == null) return; - if (LastReceivedCharacterData == null) return; + var handler = TryGetHandler(); + if (handler is null) + { + _logger.LogTrace("ApplyLastReceivedData skipped for {Uid}: handler missing.", UserData.UID); + return; + } - CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced); + handler.ApplyLastReceivedData(forced); } public void CreateCachedPlayer(OnlineUserIdentDto? dto = null) { - try + var handler = TryGetHandler(); + if (handler is null) { - _creationSemaphore.Wait(); - - if (CachedPlayer != null) return; - - if (dto == null && _onlineUserIdentDto == null) - { - CachedPlayer?.Dispose(); - CachedPlayer = null; - return; - } - if (dto != null) - { - _onlineUserIdentDto = dto; - } - - CachedPlayer?.Dispose(); - CachedPlayer = _cachedPlayerFactory.Create(this); + _logger.LogTrace("CreateCachedPlayer skipped for {Uid}: handler unavailable.", UserData.UID); + return; } - finally + + if (!handler.Initialized) { - _creationSemaphore.Release(); + handler.Initialize(); } } @@ -178,7 +178,7 @@ public class Pair public string GetPlayerNameHash() { - return CachedPlayer?.PlayerNameHash ?? string.Empty; + return TryGetHandler()?.PlayerNameHash ?? string.Empty; } public bool HasAnyConnection() @@ -188,21 +188,7 @@ public class Pair public void MarkOffline(bool wait = true) { - try - { - if (wait) - _creationSemaphore.Wait(); - LastReceivedCharacterData = null; - var player = CachedPlayer; - CachedPlayer = null; - player?.Dispose(); - _onlineUserIdentDto = null; - } - finally - { - if (wait) - _creationSemaphore.Release(); - } + _logger.LogTrace("MarkOffline invoked for {Uid} (wait: {Wait}). New registry handles handler disposal.", UserData.UID, wait); } public void SetNote(string note) @@ -212,47 +198,12 @@ public class Pair internal void SetIsUploading() { - CachedPlayer?.SetUploading(); - } - - private CharacterData? RemoveNotSyncedFiles(CharacterData? data) - { - _logger.LogTrace("Removing not synced files"); - if (data == null) + var handler = TryGetHandler(); + if (handler is null) { - _logger.LogTrace("Nothing to remove"); - return data; + return; } - bool disableIndividualAnimations = (UserPair.OtherPermissions.IsDisableAnimations() || UserPair.OwnPermissions.IsDisableAnimations()); - bool disableIndividualVFX = (UserPair.OtherPermissions.IsDisableVFX() || UserPair.OwnPermissions.IsDisableVFX()); - bool disableIndividualSounds = (UserPair.OtherPermissions.IsDisableSounds() || UserPair.OwnPermissions.IsDisableSounds()); - - _logger.LogTrace("Disable: Sounds: {disableIndividualSounds}, Anims: {disableIndividualAnims}; " + - "VFX: {disableGroupSounds}", - disableIndividualSounds, disableIndividualAnimations, disableIndividualVFX); - - if (disableIndividualAnimations || disableIndividualSounds || disableIndividualVFX) - { - _logger.LogTrace("Data cleaned up: Animations disabled: {disableAnimations}, Sounds disabled: {disableSounds}, VFX disabled: {disableVFX}", - disableIndividualAnimations, disableIndividualSounds, disableIndividualVFX); - foreach (var objectKind in data.FileReplacements.Select(k => k.Key)) - { - if (disableIndividualSounds) - data.FileReplacements[objectKind] = data.FileReplacements[objectKind] - .Where(f => !f.GamePaths.Any(p => p.EndsWith("scd", StringComparison.OrdinalIgnoreCase))) - .ToList(); - if (disableIndividualAnimations) - data.FileReplacements[objectKind] = data.FileReplacements[objectKind] - .Where(f => !f.GamePaths.Any(p => p.EndsWith("tmb", StringComparison.OrdinalIgnoreCase) || p.EndsWith("pap", StringComparison.OrdinalIgnoreCase))) - .ToList(); - if (disableIndividualVFX) - data.FileReplacements[objectKind] = data.FileReplacements[objectKind] - .Where(f => !f.GamePaths.Any(p => p.EndsWith("atex", StringComparison.OrdinalIgnoreCase) || p.EndsWith("avfx", StringComparison.OrdinalIgnoreCase))) - .ToList(); - } - } - - return data; + handler.SetUploading(true); } -} \ No newline at end of file +} diff --git a/LightlessSync/PlayerData/Pairs/PairCoordinator.cs b/LightlessSync/PlayerData/Pairs/PairCoordinator.cs new file mode 100644 index 0000000..ddc4adb --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/PairCoordinator.cs @@ -0,0 +1,553 @@ +using System; +using System.Collections.Concurrent; +using LightlessSync.API.Data; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Data.Extensions; +using LightlessSync.API.Dto.CharaData; +using LightlessSync.API.Dto.Group; +using LightlessSync.API.Dto.User; +using LightlessSync.LightlessConfiguration; +using LightlessSync.LightlessConfiguration.Models; +using LightlessSync.Services.Mediator; +using LightlessSync.Services.Events; +using LightlessSync.Services.ServerConfiguration; +using Microsoft.Extensions.Logging; + +namespace LightlessSync.PlayerData.Pairs; + +public sealed class PairCoordinator : MediatorSubscriberBase +{ + private readonly ILogger _logger; + private readonly LightlessConfigService _configService; + private readonly LightlessMediator _mediator; + private readonly PairHandlerRegistry _handlerRegistry; + private readonly PairManager _pairManager; + private readonly PairLedger _pairLedger; + private readonly ServerConfigurationManager _serverConfigurationManager; + private readonly ConcurrentDictionary _pendingCharacterData = new(StringComparer.Ordinal); + + public PairCoordinator( + ILogger logger, + LightlessConfigService configService, + LightlessMediator mediator, + PairHandlerRegistry handlerRegistry, + PairManager pairManager, + PairLedger pairLedger, + ServerConfigurationManager serverConfigurationManager) + : base(logger, mediator) + { + _logger = logger; + _configService = configService; + _mediator = mediator; + _handlerRegistry = handlerRegistry; + _pairManager = pairManager; + _pairLedger = pairLedger; + _serverConfigurationManager = serverConfigurationManager; + + mediator.Subscribe(this, msg => HandleActiveServerChange(msg.ServerUrl)); + mediator.Subscribe(this, _ => HandleDisconnected()); + } + + internal PairLedger Ledger => _pairLedger; + + private void PublishPairDataChanged(bool groupChanged = false) + { + _mediator.Publish(new RefreshUiMessage()); + _mediator.Publish(new PairDataChangedMessage()); + if (groupChanged) + { + _mediator.Publish(new GroupCollectionChangedMessage()); + } + } + + private void NotifyUserOnline(PairConnection? connection, bool sendNotification) + { + if (connection is null) + { + return; + } + + var config = _configService.Current; + if (config.ShowOnlineNotifications && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Pair {Uid} marked online", connection.User.UID); + } + + if (!sendNotification || !config.ShowOnlineNotifications) + { + return; + } + + if (config.ShowOnlineNotificationsOnlyForIndividualPairs && + (!connection.IsDirectlyPaired || connection.IsOneSided)) + { + return; + } + + var note = _serverConfigurationManager.GetNoteForUid(connection.User.UID); + if (config.ShowOnlineNotificationsOnlyForNamedPairs && + string.IsNullOrEmpty(note)) + { + return; + } + + var message = !string.IsNullOrEmpty(note) + ? $"{note} ({connection.User.AliasOrUID}) is now online" + : $"{connection.User.AliasOrUID} is now online"; + + _mediator.Publish(new NotificationMessage("User online", message, NotificationType.Info, TimeSpan.FromSeconds(5))); + } + + private void ReapplyLastKnownData(string userId, string ident, bool forced = false) + { + var result = _handlerRegistry.ApplyLastReceivedData(new PairUniqueIdentifier(userId), ident, forced); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to reapply cached data for {Uid}: {Error}", userId, result.Error); + } + } + + public void HandleGroupChangePermissions(GroupPermissionDto dto) + { + var result = _pairManager.UpdateGroupPermissions(dto); + if (!result.Success) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update permissions for group {GroupId}: {Error}", dto.Group.GID, result.Error); + } + return; + } + + PublishPairDataChanged(groupChanged: true); + } + + public void HandleGroupFullInfo(GroupFullInfoDto dto) + { + var result = _pairManager.AddGroup(dto); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to add group {GroupId}: {Error}", dto.Group.GID, result.Error); + return; + } + + PublishPairDataChanged(groupChanged: true); + } + + public void HandleGroupPairJoined(GroupPairFullInfoDto dto) + { + var result = _pairManager.AddOrUpdateGroupPair(dto); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to add group pair {Uid}/{Group}: {Error}", dto.User.UID, dto.Group.GID, result.Error); + return; + } + + PublishPairDataChanged(groupChanged: true); + } + + private void HandleActiveServerChange(string serverUrl) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Active server changed to {Server}", serverUrl); + } + + ResetPairState(); + } + + private void HandleDisconnected() + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Lightless disconnected, clearing pair state"); + } + + ResetPairState(); + } + + private void ResetPairState() + { + _handlerRegistry.ResetAllHandlers(); + _pairManager.ClearAll(); + _pendingCharacterData.Clear(); + _mediator.Publish(new ClearProfileUserDataMessage()); + _mediator.Publish(new ClearProfileGroupDataMessage()); + PublishPairDataChanged(groupChanged: true); + } + + public void HandleGroupPairLeft(GroupPairDto dto) + { + var deregistration = _pairManager.RemoveGroupPair(dto); + if (deregistration.Success && deregistration.Value is { } registration && registration.CharacterIdent is not null) + { + _ = _handlerRegistry.DeregisterOfflinePair(registration, forceDisposal: true); + } + else if (!deregistration.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("RemoveGroupPair failed for {Uid}: {Error}", dto.User.UID, deregistration.Error); + } + + if (deregistration.Success) + { + PublishPairDataChanged(groupChanged: true); + } + } + + public void HandleGroupRemoved(GroupDto dto) + { + var removalResult = _pairManager.RemoveGroup(dto.Group.GID); + if (removalResult.Success) + { + foreach (var registration in removalResult.Value) + { + if (registration.CharacterIdent is not null) + { + _ = _handlerRegistry.DeregisterOfflinePair(registration, forceDisposal: true); + } + } + } + else if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to remove group {Group}: {Error}", dto.Group.GID, removalResult.Error); + } + + if (removalResult.Success) + { + PublishPairDataChanged(groupChanged: true); + } + } + + public void HandleGroupInfoUpdate(GroupInfoDto dto) + { + var result = _pairManager.UpdateGroupInfo(dto); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update group info for {Group}: {Error}", dto.Group.GID, result.Error); + return; + } + + PublishPairDataChanged(groupChanged: true); + } + + public void HandleGroupPairPermissions(GroupPairUserPermissionDto dto) + { + var result = _pairManager.UpdateGroupPairPermissions(dto); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update group pair permissions for {Group}: {Error}", dto.Group.GID, result.Error); + return; + } + + PublishPairDataChanged(groupChanged: true); + } + + public void HandleGroupPairStatus(GroupPairUserInfoDto dto, bool isSelf) + { + PairOperationResult result; + if (isSelf) + { + result = _pairManager.UpdateGroupStatus(dto); + } + else + { + result = _pairManager.UpdateGroupPairStatus(dto); + } + + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update group status for {Group}:{Uid}: {Error}", dto.GID, dto.UID, result.Error); + return; + } + + PublishPairDataChanged(groupChanged: true); + } + + public void HandleUserAddPair(UserPairDto dto, bool addToLastAddedUser = true) + { + var result = _pairManager.AddOrUpdateIndividual(dto, addToLastAddedUser); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to add/update pair {Uid}: {Error}", dto.User.UID, result.Error); + return; + } + + PublishPairDataChanged(); + } + + public void HandleUserAddPair(UserFullPairDto dto) + { + var result = _pairManager.AddOrUpdateIndividual(dto); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to add/update full pair {Uid}: {Error}", dto.User.UID, result.Error); + return; + } + + PublishPairDataChanged(); + } + + public void HandleUserRemovePair(UserDto dto) + { + var removal = _pairManager.RemoveIndividual(dto); + if (removal.Success && removal.Value is { } registration && registration.CharacterIdent is not null) + { + _ = _handlerRegistry.DeregisterOfflinePair(registration, forceDisposal: true); + } + else if (!removal.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("RemoveIndividual failed for {Uid}: {Error}", dto.User.UID, removal.Error); + } + + if (removal.Success) + { + _pendingCharacterData.TryRemove(dto.User.UID, out _); + PublishPairDataChanged(); + } + } + + public void HandleUserStatus(UserIndividualPairStatusDto dto) + { + var result = _pairManager.SetIndividualStatus(dto); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update individual pair status for {Uid}: {Error}", dto.User.UID, result.Error); + return; + } + + PublishPairDataChanged(); + } + + public void HandleUserOnline(OnlineUserIdentDto dto, bool sendNotification) + { + var wasOnline = false; + PairConnection? previousConnection = null; + if (_pairManager.TryGetPair(dto.User.UID, out var existingConnection)) + { + previousConnection = existingConnection; + wasOnline = existingConnection.IsOnline; + } + + var registrationResult = _pairManager.MarkOnline(dto); + if (!registrationResult.Success) + { + _logger.LogDebug("MarkOnline failed for {Uid}: {Error}", dto.User.UID, registrationResult.Error); + return; + } + + var registration = registrationResult.Value; + if (registration.CharacterIdent is null) + { + _logger.LogDebug("Online registration for {Uid} missing ident.", dto.User.UID); + } + else + { + var handlerResult = _handlerRegistry.RegisterOnlinePair(registration); + if (!handlerResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("RegisterOnlinePair failed for {Uid}: {Error}", dto.User.UID, handlerResult.Error); + } + } + + var connectionResult = _pairManager.GetPair(dto.User.UID); + var connection = connectionResult.Success ? connectionResult.Value : previousConnection; + if (connection is not null) + { + _mediator.Publish(new ClearProfileUserDataMessage(connection.User)); + } + else + { + _mediator.Publish(new ClearProfileUserDataMessage(dto.User)); + } + + if (!wasOnline) + { + NotifyUserOnline(connection, sendNotification); + } + + if (registration.CharacterIdent is not null && + _pendingCharacterData.TryRemove(dto.User.UID, out var pendingData)) + { + var pendingRegistration = new PairRegistration(new PairUniqueIdentifier(dto.User.UID), registration.CharacterIdent); + var pendingApply = _handlerRegistry.ApplyCharacterData(pendingRegistration, pendingData); + if (!pendingApply.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Applying pending character data for {Uid} failed: {Error}", dto.User.UID, pendingApply.Error); + } + } + + PublishPairDataChanged(); + } + + public void HandleUserOffline(UserData user) + { + var registrationResult = _pairManager.MarkOffline(user); + if (registrationResult.Success) + { + _pendingCharacterData.TryRemove(user.UID, out _); + if (registrationResult.Value.CharacterIdent is not null) + { + _ = _handlerRegistry.DeregisterOfflinePair(registrationResult.Value); + } + + _mediator.Publish(new ClearProfileUserDataMessage(user)); + PublishPairDataChanged(); + } + else if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("MarkOffline failed for {Uid}: {Error}", user.UID, registrationResult.Error); + } + } + + public void HandleUserPermissions(UserPermissionsDto dto) + { + var pairResult = _pairManager.GetPair(dto.User.UID); + if (!pairResult.Success) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Permission update received for unknown pair {Uid}", dto.User.UID); + } + return; + } + + var connection = pairResult.Value; + var previous = connection.OtherToSelfPermissions; + + var updateResult = _pairManager.UpdateOtherPermissions(dto); + if (!updateResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update permissions for {Uid}: {Error}", dto.User.UID, updateResult.Error); + return; + } + + PublishPairDataChanged(); + + if (previous.IsPaused() != dto.Permissions.IsPaused()) + { + _mediator.Publish(new ClearProfileUserDataMessage(dto.User)); + + if (connection.Ident is not null) + { + var pauseResult = _handlerRegistry.SetPausedState(new PairUniqueIdentifier(dto.User.UID), connection.Ident, dto.Permissions.IsPaused()); + if (!pauseResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update pause state for {Uid}: {Error}", dto.User.UID, pauseResult.Error); + } + } + } + + if (!connection.IsPaused && connection.Ident is not null) + { + ReapplyLastKnownData(dto.User.UID, connection.Ident); + } + } + + public void HandleSelfPermissions(UserPermissionsDto dto) + { + var pairResult = _pairManager.GetPair(dto.User.UID); + if (!pairResult.Success) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Self permission update received for unknown pair {Uid}", dto.User.UID); + } + return; + } + + var connection = pairResult.Value; + var previous = connection.SelfToOtherPermissions; + + var updateResult = _pairManager.UpdateSelfPermissions(dto); + if (!updateResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update self permissions for {Uid}: {Error}", dto.User.UID, updateResult.Error); + return; + } + + PublishPairDataChanged(); + + if (previous.IsPaused() != dto.Permissions.IsPaused()) + { + _mediator.Publish(new ClearProfileUserDataMessage(dto.User)); + + if (connection.Ident is not null) + { + var pauseResult = _handlerRegistry.SetPausedState(new PairUniqueIdentifier(dto.User.UID), connection.Ident, dto.Permissions.IsPaused()); + if (!pauseResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to update pause state for {Uid}: {Error}", dto.User.UID, pauseResult.Error); + } + } + } + + if (!connection.IsPaused && connection.Ident is not null) + { + ReapplyLastKnownData(dto.User.UID, connection.Ident); + } + } + + public void HandleUploadStatus(UserDto dto) + { + var pairResult = _pairManager.GetPair(dto.User.UID); + if (!pairResult.Success) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Upload status received for unknown pair {Uid}", dto.User.UID); + } + return; + } + + var connection = pairResult.Value; + if (connection.Ident is null) + { + return; + } + + var setResult = _handlerRegistry.SetUploading(new PairUniqueIdentifier(dto.User.UID), connection.Ident, true); + if (!setResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to set uploading for {Uid}: {Error}", dto.User.UID, setResult.Error); + } + } + + public void HandleCharacterData(OnlineUserCharaDataDto dto) + { + var pairResult = _pairManager.GetPair(dto.User.UID); + if (!pairResult.Success) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Character data received for unknown pair {Uid}, queued for later.", dto.User.UID); + } + _pendingCharacterData[dto.User.UID] = dto; + return; + } + + var connection = pairResult.Value; + _mediator.Publish(new EventMessage(new Event(connection.User, nameof(PairCoordinator), EventSeverity.Informational, "Received Character Data"))); + if (connection.Ident is null) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Character data received for {Uid} without ident, queued for later.", dto.User.UID); + } + _pendingCharacterData[dto.User.UID] = dto; + return; + } + + _pendingCharacterData.TryRemove(dto.User.UID, out _); + var registration = new PairRegistration(new PairUniqueIdentifier(dto.User.UID), connection.Ident); + var applyResult = _handlerRegistry.ApplyCharacterData(registration, dto); + if (!applyResult.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("ApplyCharacterData queued for {Uid}: {Error}", dto.User.UID, applyResult.Error); + } + } + + public void HandleProfile(UserDto dto) + { + _mediator.Publish(new ClearProfileUserDataMessage(dto.User)); + } +} diff --git a/LightlessSync/PlayerData/Pairs/PairHandlerAdapter.cs b/LightlessSync/PlayerData/Pairs/PairHandlerAdapter.cs new file mode 100644 index 0000000..a0239c2 --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/PairHandlerAdapter.cs @@ -0,0 +1,1835 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LightlessSync.API.Data; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Data.Extensions; +using LightlessSync.FileCache; +using LightlessSync.Interop.Ipc; +using LightlessSync.PlayerData.Factories; +using LightlessSync.PlayerData.Handlers; +using LightlessSync.Services; +using LightlessSync.Services.Events; +using LightlessSync.Services.Mediator; +using LightlessSync.Services.ServerConfiguration; +using LightlessSync.Services.TextureCompression; +using LightlessSync.Utils; +using LightlessSync.WebAPI.Files; +using LightlessSync.WebAPI.Files.Models; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using ObjectKind = LightlessSync.API.Data.Enum.ObjectKind; + +namespace LightlessSync.PlayerData.Pairs; + +public interface IPairHandlerAdapter : IDisposable, IPairPerformanceSubject +{ + string Ident { get; } + bool Initialized { get; } + bool IsVisible { get; } + bool ScheduledForDeletion { get; set; } + CharacterData? LastReceivedCharacterData { get; } + long LastAppliedDataBytes { get; } + string? PlayerName { get; } + string PlayerNameHash { get; } + uint PlayerCharacterId { get; } + + void Initialize(); + void ApplyData(CharacterData data); + void ApplyLastReceivedData(bool forced = false); + void LoadCachedCharacterData(CharacterData data); + void SetUploading(bool uploading); + void SetPaused(bool paused); +} + +public interface IPairHandlerAdapterFactory +{ + IPairHandlerAdapter Create(string ident); +} + +internal sealed class PairHandlerAdapter : DisposableMediatorSubscriberBase, IPairHandlerAdapter, IPairPerformanceSubject +{ + private sealed record CombatData(Guid ApplicationId, CharacterData CharacterData, bool Forced); + + private readonly DalamudUtilService _dalamudUtil; + private readonly FileDownloadManager _downloadManager; + private readonly FileCacheManager _fileDbManager; + private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; + private readonly IpcManager _ipcManager; + private readonly IHostApplicationLifetime _lifetime; + private readonly PlayerPerformanceService _playerPerformanceService; + private readonly PairProcessingLimiter _pairProcessingLimiter; + private readonly ServerConfigurationManager _serverConfigManager; + private readonly PluginWarningNotificationService _pluginWarningNotificationManager; + private readonly TextureDownscaleService _textureDownscaleService; + private readonly PairStateCache _pairStateCache; + private readonly PairManager _pairManager; + private Guid _currentDownloadOwnerToken; + private bool _downloadInProgress; + private CancellationTokenSource? _applicationCancellationTokenSource = new(); + private Guid _applicationId; + private Task? _applicationTask; + private CharacterData? _cachedData = null; + private GameObjectHandler? _charaHandler; + private readonly Dictionary _customizeIds = []; + private CombatData? _dataReceivedInDowntime; + private CancellationTokenSource? _downloadCancellationTokenSource = new(); + private bool _forceApplyMods = false; + private bool _forceFullReapply; + private bool _isVisible; + private Guid _penumbraCollection; + private readonly object _collectionGate = new(); + private bool _redrawOnNextApplication = false; + private readonly object _initializationGate = new(); + private readonly object _pauseLock = new(); + private Task _pauseTransitionTask = Task.CompletedTask; + private bool _pauseRequested; + private int _restoreRequested; + + public string Ident { get; } + public bool Initialized { get; private set; } + public bool ScheduledForDeletion { get; set; } + + public bool IsVisible + { + get => _isVisible; + private set + { + if (_isVisible != value) + { + _isVisible = value; + if (!_isVisible) + { + ResetRestoreState(); + DisableSync(); + ResetPenumbraCollection(reason: "VisibilityLost"); + } + else if (_charaHandler is not null && _charaHandler.Address != nint.Zero) + { + _ = EnsurePenumbraCollection(); + } + var user = GetPrimaryUserData(); + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), + EventSeverity.Informational, "User Visibility Changed, now: " + (_isVisible ? "Is Visible" : "Is not Visible")))); + Mediator.Publish(new RefreshUiMessage()); + Mediator.Publish(new VisibilityChange()); + } + } + } + + public long LastAppliedDataBytes { get; private set; } + public long LastAppliedDataTris { get; set; } = -1; + public long LastAppliedApproximateVRAMBytes { get; set; } = -1; + public long LastAppliedApproximateEffectiveVRAMBytes { get; set; } = -1; + public CharacterData? LastReceivedCharacterData { get; private set; } + + public PairHandlerAdapter( + ILogger logger, + LightlessMediator mediator, + PairManager pairManager, + string ident, + GameObjectHandlerFactory gameObjectHandlerFactory, + IpcManager ipcManager, + FileDownloadManager transferManager, + PluginWarningNotificationService pluginWarningNotificationManager, + DalamudUtilService dalamudUtil, + IHostApplicationLifetime lifetime, + FileCacheManager fileDbManager, + PlayerPerformanceService playerPerformanceService, + PairProcessingLimiter pairProcessingLimiter, + ServerConfigurationManager serverConfigManager, + TextureDownscaleService textureDownscaleService, + PairStateCache pairStateCache) : base(logger, mediator) + { + _pairManager = pairManager; + Ident = ident; + _gameObjectHandlerFactory = gameObjectHandlerFactory; + _ipcManager = ipcManager; + _downloadManager = transferManager; + _pluginWarningNotificationManager = pluginWarningNotificationManager; + _dalamudUtil = dalamudUtil; + _lifetime = lifetime; + _fileDbManager = fileDbManager; + _playerPerformanceService = playerPerformanceService; + _pairProcessingLimiter = pairProcessingLimiter; + _serverConfigManager = serverConfigManager; + _textureDownscaleService = textureDownscaleService; + _pairStateCache = pairStateCache; + LastAppliedDataBytes = -1; + } + + public void Initialize() + { + EnsureInitialized(); + } + + private void EnsureInitialized() + { + if (Initialized) + { + return; + } + + lock (_initializationGate) + { + if (Initialized) + { + return; + } + + var user = GetPrimaryUserData(); + if (LastAppliedDataBytes < 0 || LastAppliedDataTris < 0 + || LastAppliedApproximateVRAMBytes < 0 || LastAppliedApproximateEffectiveVRAMBytes < 0) + { + _forceApplyMods = true; + } + + Mediator.Subscribe(this, _ => FrameworkUpdate()); + Mediator.Subscribe(this, _ => + { + _downloadCancellationTokenSource?.CancelDispose(); + _charaHandler?.Invalidate(); + IsVisible = false; + }); + Mediator.Subscribe(this, _ => + { + ResetPenumbraCollection(releaseFromPenumbra: false, reason: "PenumbraInitialized"); + if (!IsVisible && _charaHandler is not null) + { + PlayerName = string.Empty; + _charaHandler.Dispose(); + _charaHandler = null; + } + EnableSync(); + }); + Mediator.Subscribe(this, _ => ResetPenumbraCollection(releaseFromPenumbra: false, reason: "PenumbraDisposed")); + Mediator.Subscribe(this, msg => + { + if (msg.GameObjectHandler == _charaHandler) + { + _redrawOnNextApplication = true; + } + }); + Mediator.Subscribe(this, _ => EnableSync()); + Mediator.Subscribe(this, _ => DisableSync()); + Mediator.Subscribe(this, _ => EnableSync()); + Mediator.Subscribe(this, _ => DisableSync()); + Mediator.Subscribe(this, _ => DisableSync()); + Mediator.Subscribe(this, _ => EnableSync()); + Mediator.Subscribe(this, _ => DisableSync()); + Mediator.Subscribe(this, _ => EnableSync()); + Mediator.Subscribe(this, _ => DisableSync()); + Mediator.Subscribe(this, _ => EnableSync()); + Mediator.Subscribe(this, msg => + { + if (_charaHandler is null || !ReferenceEquals(msg.DownloadId, _charaHandler)) + { + return; + } + + if (_downloadManager.CurrentOwnerToken.HasValue + && _downloadManager.CurrentOwnerToken == _currentDownloadOwnerToken) + { + TryApplyQueuedData(); + } + }); + + Initialized = true; + } + } + + private IReadOnlyList GetCurrentPairs() + { + return _pairManager.GetPairsByIdent(Ident); + } + + private PairConnection? GetPrimaryPair() + { + var pairs = GetCurrentPairs(); + var direct = pairs.FirstOrDefault(p => p.IsDirectlyPaired); + if (direct is not null) + { + return direct; + } + + var online = pairs.FirstOrDefault(p => p.IsOnline); + if (online is not null) + { + return online; + } + + return pairs.FirstOrDefault(); + } + + private UserData GetPrimaryUserData() + { + return GetPrimaryPair()?.User ?? new UserData(Ident); + } + + private string GetPrimaryAliasOrUid() + { + var pair = GetPrimaryPair(); + if (pair?.User is null) + { + return Ident; + } + + return string.IsNullOrEmpty(pair.User.AliasOrUID) ? Ident : pair.User.AliasOrUID; + } + + private string GetPrimaryAliasOrUidSafe() + { + try + { + return GetPrimaryAliasOrUid(); + } + catch + { + return Ident; + } + } + + private UserData GetPrimaryUserDataSafe() + { + try + { + return GetPrimaryUserData(); + } + catch + { + return new UserData(Ident); + } + } + + private string GetLogIdentifier() + { + var alias = GetPrimaryAliasOrUidSafe(); + return string.Equals(alias, Ident, StringComparison.Ordinal) ? alias : $"{alias} ({Ident})"; + } + + private Guid EnsurePenumbraCollection() + { + if (!IsVisible) + { + return Guid.Empty; + } + + if (_penumbraCollection != Guid.Empty) + { + return _penumbraCollection; + } + + lock (_collectionGate) + { + if (_penumbraCollection != Guid.Empty) + { + return _penumbraCollection; + } + + var cached = _pairStateCache.TryGetTemporaryCollection(Ident); + if (cached.HasValue && cached.Value != Guid.Empty) + { + _penumbraCollection = cached.Value; + return _penumbraCollection; + } + + if (!_ipcManager.Penumbra.APIAvailable) + { + return Guid.Empty; + } + + var user = GetPrimaryUserDataSafe(); + var uid = !string.IsNullOrEmpty(user.UID) ? user.UID : Ident; + var created = _ipcManager.Penumbra.CreateTemporaryCollectionAsync(Logger, uid) + .ConfigureAwait(false).GetAwaiter().GetResult(); + if (created != Guid.Empty) + { + _penumbraCollection = created; + _pairStateCache.StoreTemporaryCollection(Ident, created); + } + + return _penumbraCollection; + } + } + + private void ResetPenumbraCollection(bool releaseFromPenumbra = true, string? reason = null) + { + Guid toRelease = Guid.Empty; + lock (_collectionGate) + { + if (_penumbraCollection != Guid.Empty) + { + toRelease = _penumbraCollection; + _penumbraCollection = Guid.Empty; + } + } + + var cached = _pairStateCache.ClearTemporaryCollection(Ident); + if (cached.HasValue && cached.Value != Guid.Empty) + { + toRelease = cached.Value; + } + + if (!releaseFromPenumbra || toRelease == Guid.Empty || !_ipcManager.Penumbra.APIAvailable) + { + return; + } + + try + { + var applicationId = Guid.NewGuid(); + Logger.LogTrace("[{applicationId}] Removing temp collection {CollectionId} for {handler} ({reason})", applicationId, toRelease, GetLogIdentifier(), reason ?? "Cleanup"); + _ipcManager.Penumbra.RemoveTemporaryCollectionAsync(Logger, applicationId, toRelease).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to remove temporary Penumbra collection for {handler}", GetLogIdentifier()); + } + } + + private bool AnyPair(Func predicate) + { + return GetCurrentPairs().Any(predicate); + } + + private bool ShouldSkipDownscale() + { + return GetCurrentPairs().Any(p => p.IsDirectlyPaired && p.SelfToOtherPermissions.IsSticky()); + } + + private bool IsPaused() + { + var pairs = GetCurrentPairs(); + return pairs.Count > 0 && pairs.Any(p => p.IsPaused); + } + + bool IPairPerformanceSubject.IsPaused => IsPaused(); + + bool IPairPerformanceSubject.IsDirectlyPaired => AnyPair(p => p.IsDirectlyPaired); + + bool IPairPerformanceSubject.HasStickyPermissions => AnyPair(p => p.SelfToOtherPermissions.HasFlag(UserPermissions.Sticky)); + + UserData IPairPerformanceSubject.UserData => GetPrimaryUserData(); + + string IPairPerformanceSubject.PlayerName => PlayerName ?? GetPrimaryAliasOrUidSafe(); + private UserPermissions GetCombinedPermissions() + { + var pairs = GetCurrentPairs(); + if (pairs.Count == 0) + { + return UserPermissions.NoneSet; + } + + var combined = pairs[0].SelfToOtherPermissions | pairs[0].OtherToSelfPermissions; + for (int i = 1; i < pairs.Count; i++) + { + var perms = pairs[i].SelfToOtherPermissions | pairs[i].OtherToSelfPermissions; + combined &= perms; + } + + return combined; + } + public nint PlayerCharacter => _charaHandler?.Address ?? nint.Zero; + public unsafe uint PlayerCharacterId => (_charaHandler?.Address ?? nint.Zero) == nint.Zero + ? uint.MaxValue + : ((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_charaHandler!.Address)->EntityId; + public string? PlayerName { get; private set; } + public string PlayerNameHash => Ident; + + public void ApplyData(CharacterData data) + { + EnsureInitialized(); + LastReceivedCharacterData = data; + ResetRestoreState(); + ApplyLastReceivedData(); + } + + public void LoadCachedCharacterData(CharacterData data) + { + if (data is null) + { + return; + } + + LastReceivedCharacterData = data; + ResetRestoreState(); + _cachedData = null; + _forceApplyMods = true; + _forceFullReapply = true; + LastAppliedDataBytes = -1; + LastAppliedDataTris = -1; + LastAppliedApproximateVRAMBytes = -1; + LastAppliedApproximateEffectiveVRAMBytes = -1; + } + + public void ApplyLastReceivedData(bool forced = false) + { + EnsureInitialized(); + if (LastReceivedCharacterData is null) + { + Logger.LogTrace("No cached data to apply for {Ident}", Ident); + if (forced) + { + EnsureRestoredStateWhileWaitingForData("ForcedReapplyWithoutCache", skipIfAlreadyRestored: false); + } + return; + } + + var shouldForce = forced || HasMissingCachedFiles(LastReceivedCharacterData); + + if (IsPaused()) + { + Logger.LogTrace("Permissions paused for {Ident}, skipping reapply", Ident); + return; + } + + if (shouldForce) + { + _forceApplyMods = true; + _cachedData = null; + _forceFullReapply = true; + LastAppliedDataBytes = -1; + LastAppliedDataTris = -1; + LastAppliedApproximateVRAMBytes = -1; + LastAppliedApproximateEffectiveVRAMBytes = -1; + } + + var sanitized = RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone()); + if (sanitized is null) + { + Logger.LogTrace("Sanitized data null for {Ident}", Ident); + return; + } + + _pairStateCache.Store(Ident, sanitized); + + if (!IsVisible) + { + Logger.LogTrace("Handler for {Ident} not visible, caching sanitized data for later", Ident); + _cachedData = sanitized; + _forceFullReapply = true; + return; + } + + ApplyCharacterData(Guid.NewGuid(), sanitized, shouldForce); + } + + private bool HasMissingCachedFiles(CharacterData characterData) + { + try + { + HashSet inspectedHashes = new(StringComparer.OrdinalIgnoreCase); + foreach (var replacements in characterData.FileReplacements.Values) + { + foreach (var replacement in replacements) + { + if (!string.IsNullOrEmpty(replacement.FileSwapPath)) + { + if (!File.Exists(replacement.FileSwapPath)) + { + Logger.LogTrace("Missing file swap path {Path} detected for {Handler}", replacement.FileSwapPath, GetLogIdentifier()); + return true; + } + continue; + } + + if (string.IsNullOrEmpty(replacement.Hash) || !inspectedHashes.Add(replacement.Hash)) + { + continue; + } + + var cacheEntry = _fileDbManager.GetFileCacheByHash(replacement.Hash); + if (cacheEntry is null) + { + Logger.LogTrace("Missing cached file {Hash} detected for {Handler}", replacement.Hash, GetLogIdentifier()); + return true; + } + + if (!File.Exists(cacheEntry.ResolvedFilepath)) + { + Logger.LogTrace("Cached file {Hash} missing on disk for {Handler}, removing cache entry", replacement.Hash, GetLogIdentifier()); + _fileDbManager.RemoveHashedFile(cacheEntry.Hash, cacheEntry.PrefixedFilePath); + return true; + } + } + } + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to determine cache availability for {Handler}", GetLogIdentifier()); + } + + return false; + } + + private CharacterData? RemoveNotSyncedFiles(CharacterData? data) + { + Logger.LogTrace("Removing not synced files for {Ident}", Ident); + if (data is null) + { + return null; + } + + var permissions = GetCombinedPermissions(); + bool disableAnimations = permissions.IsDisableAnimations(); + bool disableVfx = permissions.IsDisableVFX(); + bool disableSounds = permissions.IsDisableSounds(); + + if (!(disableAnimations || disableVfx || disableSounds)) + { + return data; + } + + foreach (var objectKind in data.FileReplacements.Keys.ToList()) + { + var replacements = data.FileReplacements[objectKind]; + if (disableSounds) + { + replacements = replacements + .Where(f => !f.GamePaths.Any(p => p.EndsWith("scd", StringComparison.OrdinalIgnoreCase))) + .ToList(); + } + + if (disableAnimations) + { + replacements = replacements + .Where(f => !f.GamePaths.Any(p => + p.EndsWith("tmb", StringComparison.OrdinalIgnoreCase) || + p.EndsWith("pap", StringComparison.OrdinalIgnoreCase))) + .ToList(); + } + + if (disableVfx) + { + replacements = replacements + .Where(f => !f.GamePaths.Any(p => + p.EndsWith("atex", StringComparison.OrdinalIgnoreCase) || + p.EndsWith("avfx", StringComparison.OrdinalIgnoreCase))) + .ToList(); + } + + data.FileReplacements[objectKind] = replacements; + } + + return data; + } + + private void ResetRestoreState() + { + Volatile.Write(ref _restoreRequested, 0); + } + + private void EnsureRestoredStateWhileWaitingForData(string reason, bool skipIfAlreadyRestored = true) + { + if (!IsVisible || _charaHandler is null || _charaHandler.Address == nint.Zero) + { + return; + } + + if (_cachedData is not null || LastReceivedCharacterData is not null) + { + return; + } + + if (!skipIfAlreadyRestored) + { + ResetRestoreState(); + } + else if (Volatile.Read(ref _restoreRequested) == 1) + { + return; + } + + if (Interlocked.CompareExchange(ref _restoreRequested, 1, 0) != 0) + { + return; + } + + var applicationId = Guid.NewGuid(); + _ = Task.Run(async () => + { + try + { + Logger.LogDebug("[{applicationId}] Restoring vanilla state for {handler} while waiting for data ({reason})", applicationId, GetLogIdentifier(), reason); + await RevertToRestoredAsync(applicationId).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "[{applicationId}] Failed to restore vanilla state for {handler} ({reason})", applicationId, GetLogIdentifier(), reason); + ResetRestoreState(); + } + }); + } + + private static Dictionary> BuildFullChangeSet(CharacterData characterData) + { + var result = new Dictionary>(); + + foreach (var objectKind in Enum.GetValues()) + { + var changes = new HashSet(); + + if (characterData.FileReplacements.TryGetValue(objectKind, out var replacements) && replacements.Count > 0) + { + changes.Add(PlayerChanges.ModFiles); + if (objectKind == ObjectKind.Player) + { + changes.Add(PlayerChanges.ForcedRedraw); + } + } + + if (characterData.GlamourerData.TryGetValue(objectKind, out var glamourer) && !string.IsNullOrEmpty(glamourer)) + { + changes.Add(PlayerChanges.Glamourer); + } + + if (characterData.CustomizePlusData.TryGetValue(objectKind, out var customize) && !string.IsNullOrEmpty(customize)) + { + changes.Add(PlayerChanges.Customize); + } + + if (objectKind == ObjectKind.Player) + { + if (!string.IsNullOrEmpty(characterData.ManipulationData)) + { + changes.Add(PlayerChanges.ModManip); + changes.Add(PlayerChanges.ForcedRedraw); + } + + if (!string.IsNullOrEmpty(characterData.HeelsData)) + { + changes.Add(PlayerChanges.Heels); + } + + if (!string.IsNullOrEmpty(characterData.HonorificData)) + { + changes.Add(PlayerChanges.Honorific); + } + + if (!string.IsNullOrEmpty(characterData.MoodlesData)) + { + changes.Add(PlayerChanges.Moodles); + } + + if (!string.IsNullOrEmpty(characterData.PetNamesData)) + { + changes.Add(PlayerChanges.PetNames); + } + } + + if (changes.Count > 0) + { + result[objectKind] = changes; + } + } + + return result; + } + + private bool CanApplyNow() + { + return !_dalamudUtil.IsInCombat + && !_dalamudUtil.IsPerforming + && !_dalamudUtil.IsInInstance + && !_dalamudUtil.IsInCutscene + && !_dalamudUtil.IsInGpose + && _ipcManager.Penumbra.APIAvailable + && _ipcManager.Glamourer.APIAvailable; + } + + public void ApplyCharacterData(Guid applicationBase, CharacterData characterData, bool forceApplyCustomization = false) + { + if (characterData is null) + { + Logger.LogWarning("[BASE-{appBase}] Received null character data, skipping application for {handler}", applicationBase, GetLogIdentifier()); + SetUploading(isUploading: false); + return; + } + + var user = GetPrimaryUserData(); + if (_dalamudUtil.IsInCombat) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: you are in combat, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player is in combat", applicationBase); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + + if (_dalamudUtil.IsPerforming) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: you are performing music, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player is performing", applicationBase); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + + if (_dalamudUtil.IsInInstance) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: you are in an instance, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player is in instance", applicationBase); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + + if (_dalamudUtil.IsInCutscene) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: you are in a cutscene, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player is in a cutscene", applicationBase); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + + if (_dalamudUtil.IsInGpose) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: you are in GPose, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player is in GPose", applicationBase); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + + if (!_ipcManager.Penumbra.APIAvailable || !_ipcManager.Glamourer.APIAvailable) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: Penumbra or Glamourer is not available, deferring application"))); + Logger.LogInformation("[BASE-{appbase}] Application of data for {player} while Penumbra/Glamourer unavailable, returning", applicationBase, GetLogIdentifier()); + _dataReceivedInDowntime = new(applicationBase, characterData, forceApplyCustomization); + SetUploading(isUploading: false); + return; + } + + var handlerReady = _charaHandler is not null && PlayerCharacter != IntPtr.Zero; + + if (!handlerReady) + { + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Warning, + "Cannot apply character data: Receiving Player is in an invalid state, deferring application"))); + Logger.LogDebug("[BASE-{appBase}] Received data but player was in invalid state, charaHandlerIsNull: {charaIsNull}, playerPointerIsNull: {ptrIsNull}", + applicationBase, _charaHandler == null, PlayerCharacter == IntPtr.Zero); + var hasDiffMods = characterData.CheckUpdatedData(applicationBase, _cachedData, Logger, + this, forceApplyCustomization, forceApplyMods: false) + .Any(p => p.Value.Contains(PlayerChanges.ModManip) || p.Value.Contains(PlayerChanges.ModFiles)); + _forceApplyMods = hasDiffMods || _forceApplyMods || _cachedData == null; + _forceFullReapply = true; + _cachedData = characterData; + Logger.LogDebug("[BASE-{appBase}] Setting data: {hash}, forceApplyMods: {force}", applicationBase, _cachedData.DataHash.Value, _forceApplyMods); + } + + SetUploading(isUploading: false); + + Logger.LogDebug("[BASE-{appbase}] Applying data for {player}, forceApplyCustomization: {forced}, forceApplyMods: {forceMods}", applicationBase, GetLogIdentifier(), forceApplyCustomization, _forceApplyMods); + Logger.LogDebug("[BASE-{appbase}] Hash for data is {newHash}, current cache hash is {oldHash}", applicationBase, characterData.DataHash.Value, _cachedData?.DataHash.Value ?? "NODATA"); + + if (handlerReady + && string.Equals(characterData.DataHash.Value, _cachedData?.DataHash.Value ?? string.Empty, StringComparison.Ordinal) + && !forceApplyCustomization && !_forceApplyMods) + { + return; + } + + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Informational, + "Applying Character Data"))); + + var charaDataToUpdate = characterData.CheckUpdatedData(applicationBase, _cachedData?.DeepClone() ?? new(), Logger, this, forceApplyCustomization, _forceApplyMods); + + if (_forceFullReapply) + { + charaDataToUpdate = BuildFullChangeSet(characterData); + } + + if (handlerReady && _forceApplyMods) + { + _forceApplyMods = false; + } + + if (_redrawOnNextApplication && charaDataToUpdate.TryGetValue(ObjectKind.Player, out var player)) + { + player.Add(PlayerChanges.ForcedRedraw); + _redrawOnNextApplication = false; + } + + if (charaDataToUpdate.TryGetValue(ObjectKind.Player, out var playerChanges)) + { + _pluginWarningNotificationManager.NotifyForMissingPlugins(user, PlayerName!, playerChanges); + } + + Logger.LogDebug("[BASE-{appbase}] Downloading and applying character for {name}", applicationBase, GetPrimaryAliasOrUidSafe()); + + var forcesReapply = _forceFullReapply || forceApplyCustomization || LastAppliedApproximateVRAMBytes < 0 || LastAppliedDataTris < 0; + + DownloadAndApplyCharacter(applicationBase, characterData.DeepClone(), charaDataToUpdate, forcesReapply, forceApplyCustomization); + } + + public override string ToString() + { + var alias = GetPrimaryAliasOrUidSafe(); + return $"{alias}:{PlayerName ?? string.Empty}:{(PlayerCharacter != nint.Zero ? "HasChar" : "NoChar")}"; + } + + public void SetUploading(bool isUploading = true) + { + Logger.LogTrace("Setting {name} uploading {uploading}", GetPrimaryAliasOrUidSafe(), isUploading); + if (_charaHandler != null) + { + Mediator.Publish(new PlayerUploadingMessage(_charaHandler, isUploading)); + } + } + + public void SetPaused(bool paused) + { + lock (_pauseLock) + { + if (_pauseRequested == paused) + { + return; + } + + _pauseRequested = paused; + _pauseTransitionTask = _pauseTransitionTask + .ContinueWith(_ => paused ? PauseInternalAsync() : ResumeInternalAsync(), TaskScheduler.Default) + .Unwrap(); + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + SetUploading(isUploading: false); + var name = PlayerName; + var user = GetPrimaryUserDataSafe(); + var alias = GetPrimaryAliasOrUidSafe(); + Logger.LogDebug("Disposing {name} ({user})", name, alias); + try + { + Guid applicationId = Guid.NewGuid(); + _applicationCancellationTokenSource?.CancelDispose(); + _applicationCancellationTokenSource = null; + _downloadCancellationTokenSource?.CancelDispose(); + _downloadCancellationTokenSource = null; + _downloadManager.Dispose(); + _charaHandler?.Dispose(); + _charaHandler = null; + + if (!string.IsNullOrEmpty(name)) + { + Mediator.Publish(new EventMessage(new Event(name, user, nameof(PairHandlerAdapter), EventSeverity.Informational, "Disposing User"))); + } + + if (_lifetime.ApplicationStopping.IsCancellationRequested) return; + + if (_dalamudUtil is { IsZoning: false, IsInCutscene: false } && !string.IsNullOrEmpty(name)) + { + Logger.LogTrace("[{applicationId}] Restoring state for {name} ({user})", applicationId, name, alias); + Logger.LogDebug("[{applicationId}] Removing Temp Collection for {name} ({user})", applicationId, name, alias); + ResetPenumbraCollection(reason: nameof(Dispose)); + if (!IsVisible) + { + Logger.LogDebug("[{applicationId}] Restoring Glamourer for {name} ({user})", applicationId, name, alias); + _ipcManager.Glamourer.RevertByNameAsync(Logger, name, applicationId).GetAwaiter().GetResult(); + } + else + { + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(60)); + + var effectiveCachedData = _cachedData ?? _pairStateCache.TryLoad(Ident); + if (effectiveCachedData is not null) + { + _cachedData = effectiveCachedData; + } + + Logger.LogInformation("[{applicationId}] CachedData is null {isNull}, contains things: {contains}", + applicationId, _cachedData == null, _cachedData?.FileReplacements.Any() ?? false); + + foreach (KeyValuePair> item in _cachedData?.FileReplacements ?? []) + { + try + { + RevertCustomizationDataAsync(item.Key, name, applicationId, cts.Token).GetAwaiter().GetResult(); + } + catch (InvalidOperationException ex) + { + Logger.LogWarning(ex, "Failed disposing player (not present anymore?)"); + break; + } + } + } + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Error on disposal of {name}", name); + } + finally + { + PlayerName = null; + _cachedData = null; + Logger.LogDebug("Disposing {name} complete", name); + } + } + + private async Task ApplyCustomizationDataAsync(Guid applicationId, KeyValuePair> changes, CharacterData charaData, CancellationToken token) + { + if (PlayerCharacter == nint.Zero) return; + var ptr = PlayerCharacter; + + var handler = changes.Key switch + { + ObjectKind.Player => _charaHandler!, + ObjectKind.Companion => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetCompanionPtr(ptr), isWatched: false).ConfigureAwait(false), + ObjectKind.MinionOrMount => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetMinionOrMountPtr(ptr), isWatched: false).ConfigureAwait(false), + ObjectKind.Pet => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetPetPtr(ptr), isWatched: false).ConfigureAwait(false), + _ => throw new NotSupportedException("ObjectKind not supported: " + changes.Key) + }; + + try + { + if (handler.Address == nint.Zero) + { + return; + } + + Logger.LogDebug("[{applicationId}] Applying Customization Data for {handler}", applicationId, handler); + await _dalamudUtil.WaitWhileCharacterIsDrawing(Logger, handler, applicationId, 30000, token).ConfigureAwait(false); + token.ThrowIfCancellationRequested(); + foreach (var change in changes.Value.OrderBy(p => (int)p)) + { + Logger.LogDebug("[{applicationId}] Processing {change} for {handler}", applicationId, change, handler); + switch (change) + { + case PlayerChanges.Customize: + if (charaData.CustomizePlusData.TryGetValue(changes.Key, out var customizePlusData)) + { + _customizeIds[changes.Key] = await _ipcManager.CustomizePlus.SetBodyScaleAsync(handler.Address, customizePlusData).ConfigureAwait(false); + } + else if (_customizeIds.TryGetValue(changes.Key, out var customizeId)) + { + await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); + _customizeIds.Remove(changes.Key); + } + break; + + case PlayerChanges.Heels: + await _ipcManager.Heels.SetOffsetForPlayerAsync(handler.Address, charaData.HeelsData).ConfigureAwait(false); + break; + + case PlayerChanges.Honorific: + await _ipcManager.Honorific.SetTitleAsync(handler.Address, charaData.HonorificData).ConfigureAwait(false); + break; + + case PlayerChanges.Glamourer: + if (charaData.GlamourerData.TryGetValue(changes.Key, out var glamourerData)) + { + await _ipcManager.Glamourer.ApplyAllAsync(Logger, handler, glamourerData, applicationId, token).ConfigureAwait(false); + } + break; + + case PlayerChanges.Moodles: + await _ipcManager.Moodles.SetStatusAsync(handler.Address, charaData.MoodlesData).ConfigureAwait(false); + break; + + case PlayerChanges.PetNames: + await _ipcManager.PetNames.SetPlayerData(handler.Address, charaData.PetNamesData).ConfigureAwait(false); + break; + + case PlayerChanges.ForcedRedraw: + await _ipcManager.Penumbra.RedrawAsync(Logger, handler, applicationId, token).ConfigureAwait(false); + break; + + default: + break; + } + token.ThrowIfCancellationRequested(); + } + } + finally + { + if (handler != _charaHandler) handler.Dispose(); + } + } + + private void DownloadAndApplyCharacter(Guid applicationBase, CharacterData charaData, Dictionary> updatedData, bool forcePerformanceRecalc, bool forceApplyCustomization) + { + if (!updatedData.Any()) + { + if (forcePerformanceRecalc) + { + updatedData = BuildFullChangeSet(charaData); + } + + if (!updatedData.Any()) + { + Logger.LogDebug("[BASE-{appBase}] Nothing to update for {obj}", applicationBase, GetLogIdentifier()); + _forceFullReapply = false; + return; + } + } + + var updateModdedPaths = updatedData.Values.Any(v => v.Any(p => p == PlayerChanges.ModFiles)); + var updateManip = updatedData.Values.Any(v => v.Any(p => p == PlayerChanges.ModManip)); + + if (_downloadInProgress) + { + Logger.LogDebug("[BASE-{appBase}] Download already in progress for {handler}, queueing data", applicationBase, GetLogIdentifier()); + EnqueueDeferredCharacterData(charaData, forceApplyCustomization || _forceApplyMods); + return; + } + + _downloadCancellationTokenSource = _downloadCancellationTokenSource?.CancelRecreate() ?? new CancellationTokenSource(); + var downloadToken = _downloadCancellationTokenSource.Token; + var downloadOwnerToken = Guid.NewGuid(); + _currentDownloadOwnerToken = downloadOwnerToken; + _downloadInProgress = true; + + _ = DownloadAndApplyCharacterAsync(applicationBase, charaData, updatedData, updateModdedPaths, updateManip, forcePerformanceRecalc, downloadOwnerToken, downloadToken).ConfigureAwait(false); + } + + private Task? _pairDownloadTask; + + private async Task DownloadAndApplyCharacterAsync(Guid applicationBase, CharacterData charaData, Dictionary> updatedData, + bool updateModdedPaths, bool updateManip, bool forcePerformanceRecalc, Guid downloadOwnerToken, CancellationToken downloadToken) + { + try + { + await using var concurrencyLease = await _pairProcessingLimiter.AcquireAsync(downloadToken).ConfigureAwait(false); + Dictionary<(string GamePath, string? Hash), string> moddedPaths = []; + bool skipDownscaleForPair = ShouldSkipDownscale(); + var user = GetPrimaryUserData(); + + bool performedDownload = false; + + if (updateModdedPaths) + { + int attempts = 0; + List toDownloadReplacements = TryCalculateModdedDictionary(applicationBase, charaData, out moddedPaths, downloadToken); + Logger.LogDebug("[BASE-{appBase}] Initial missing files for {handler}: {count}", applicationBase, GetLogIdentifier(), toDownloadReplacements.Count); + + while (toDownloadReplacements.Count > 0 && attempts++ <= 10 && !downloadToken.IsCancellationRequested) + { + if (_pairDownloadTask != null && !_pairDownloadTask.IsCompleted) + { + Logger.LogDebug("[BASE-{appBase}] Finishing prior running download task for player {name}, {kind}", applicationBase, PlayerName, updatedData); + await _pairDownloadTask.ConfigureAwait(false); + } + + Logger.LogDebug("[BASE-{appBase}] Downloading missing files for player {name}, {kind}", applicationBase, PlayerName, updatedData); + + Mediator.Publish(new EventMessage(new Event(PlayerName, user, nameof(PairHandlerAdapter), EventSeverity.Informational, + $"Starting download for {toDownloadReplacements.Count} files"))); + var currentHandler = _charaHandler; + var toDownloadFiles = await _downloadManager.InitiateDownloadList(currentHandler, toDownloadReplacements, downloadToken, downloadOwnerToken).ConfigureAwait(false); + Logger.LogDebug("[BASE-{appBase}] Download plan prepared for {handler}: {current} transfers, forbidden so far: {forbidden}", applicationBase, GetLogIdentifier(), toDownloadFiles.Count, _downloadManager.ForbiddenTransfers.Count); + + if (!_playerPerformanceService.ComputeAndAutoPauseOnVRAMUsageThresholds(this, charaData, toDownloadFiles)) + { + _downloadManager.ClearDownload(); + MarkApplicationDeferred(charaData); + return; + } + + performedDownload = true; + + var handlerForDownload = currentHandler; + _pairDownloadTask = Task.Run(async () => await _downloadManager.DownloadFiles(handlerForDownload, toDownloadReplacements, downloadToken, skipDownscaleForPair).ConfigureAwait(false)); + + await _pairDownloadTask.ConfigureAwait(false); + + if (downloadToken.IsCancellationRequested) + { + Logger.LogTrace("[BASE-{appBase}] Detected cancellation", applicationBase); + MarkApplicationDeferred(charaData); + return; + } + + toDownloadReplacements = TryCalculateModdedDictionary(applicationBase, charaData, out moddedPaths, downloadToken); + + if (toDownloadReplacements.TrueForAll(c => _downloadManager.ForbiddenTransfers.Exists(f => string.Equals(f.Hash, c.Hash, StringComparison.Ordinal)))) + { + break; + } + + await Task.Delay(TimeSpan.FromSeconds(2), downloadToken).ConfigureAwait(false); + Logger.LogDebug("[BASE-{appBase}] Re-evaluating missing files for {handler}: {count} remaining after attempt {attempt}", applicationBase, GetLogIdentifier(), toDownloadReplacements.Count, attempts); + } + + if (!performedDownload) + { + if (!_playerPerformanceService.ComputeAndAutoPauseOnVRAMUsageThresholds(this, charaData, new List())) + { + _downloadManager.ClearDownload(); + MarkApplicationDeferred(charaData); + return; + } + } + + if (!await _playerPerformanceService.CheckBothThresholds(this, charaData).ConfigureAwait(false)) + { + MarkApplicationDeferred(charaData); + return; + } + } + else if (forcePerformanceRecalc) + { + if (!_playerPerformanceService.ComputeAndAutoPauseOnVRAMUsageThresholds(this, charaData, new List())) + { + MarkApplicationDeferred(charaData); + return; + } + + if (!await _playerPerformanceService.CheckBothThresholds(this, charaData).ConfigureAwait(false)) + { + MarkApplicationDeferred(charaData); + return; + } + } + + downloadToken.ThrowIfCancellationRequested(); + + var handlerForApply = _charaHandler; + if (handlerForApply is null || handlerForApply.Address == nint.Zero) + { + Logger.LogDebug("[BASE-{appBase}] Handler not available for {player}, cached data for later application", applicationBase, GetLogIdentifier()); + _cachedData = charaData; + _pairStateCache.Store(Ident, charaData); + _forceFullReapply = true; + MarkApplicationDeferred(charaData); + return; + } + + var appToken = _applicationCancellationTokenSource?.Token; + while ((!_applicationTask?.IsCompleted ?? false) + && !downloadToken.IsCancellationRequested + && (!appToken?.IsCancellationRequested ?? false)) + { + // block until current application is done + Logger.LogDebug("[BASE-{appBase}] Waiting for current data application (Id: {id}) for player ({handler}) to finish", applicationBase, _applicationId, PlayerName); + await Task.Delay(250).ConfigureAwait(false); + } + + if (downloadToken.IsCancellationRequested || (appToken?.IsCancellationRequested ?? false)) + { + MarkApplicationDeferred(charaData); + return; + } + + _applicationCancellationTokenSource = _applicationCancellationTokenSource.CancelRecreate() ?? new CancellationTokenSource(); + var token = _applicationCancellationTokenSource.Token; + + _forceFullReapply = false; + _applicationTask = ApplyCharacterDataAsync(applicationBase, handlerForApply, charaData, updatedData, updateModdedPaths, updateManip, moddedPaths, token); + } + catch (OperationCanceledException ex) when (downloadToken.IsCancellationRequested || ex.CancellationToken == downloadToken) + { + Logger.LogDebug("[BASE-{appBase}] Download cancelled for {handler}", applicationBase, GetLogIdentifier()); + MarkApplicationDeferred(charaData); + } + finally + { + _downloadInProgress = false; + } + } + + private async Task ApplyCharacterDataAsync(Guid applicationBase, GameObjectHandler handlerForApply, CharacterData charaData, Dictionary> updatedData, bool updateModdedPaths, bool updateManip, + Dictionary<(string GamePath, string? Hash), string> moddedPaths, CancellationToken token) + { + try + { + _applicationId = Guid.NewGuid(); + Logger.LogDebug("[BASE-{applicationId}] Starting application task for {handler}: {appId}", applicationBase, GetLogIdentifier(), _applicationId); + + Logger.LogDebug("[{applicationId}] Waiting for initial draw for for {handler}", _applicationId, handlerForApply); + await _dalamudUtil.WaitWhileCharacterIsDrawing(Logger, handlerForApply, _applicationId, 30000, token).ConfigureAwait(false); + + token.ThrowIfCancellationRequested(); + + Guid penumbraCollection = Guid.Empty; + if (updateModdedPaths || updateManip) + { + penumbraCollection = EnsurePenumbraCollection(); + if (penumbraCollection == Guid.Empty) + { + Logger.LogTrace("[BASE-{applicationId}] Penumbra collection unavailable for {handler}, caching data for later application", applicationBase, GetLogIdentifier()); + MarkApplicationDeferred(charaData); + return; + } + } + + if (updateModdedPaths) + { + // ensure collection is set + var objIndex = await _dalamudUtil.RunOnFrameworkThread(() => + { + var gameObject = handlerForApply.GetGameObject(); + return gameObject?.ObjectIndex; + }).ConfigureAwait(false); + + if (!objIndex.HasValue) + { + Logger.LogDebug("[BASE-{applicationId}] GameObject not available for {handler}, caching data for later application", applicationBase, GetLogIdentifier()); + MarkApplicationDeferred(charaData); + return; + } + + await _ipcManager.Penumbra.AssignTemporaryCollectionAsync(Logger, penumbraCollection, objIndex.Value).ConfigureAwait(false); + + await _ipcManager.Penumbra.SetTemporaryModsAsync(Logger, _applicationId, penumbraCollection, + moddedPaths.ToDictionary(k => k.Key.GamePath, k => k.Value, StringComparer.Ordinal)).ConfigureAwait(false); + LastAppliedDataBytes = -1; + foreach (var path in moddedPaths.Values.Distinct(StringComparer.OrdinalIgnoreCase).Select(v => new FileInfo(v)).Where(p => p.Exists)) + { + if (LastAppliedDataBytes == -1) LastAppliedDataBytes = 0; + + LastAppliedDataBytes += path.Length; + } + } + + if (updateManip) + { + await _ipcManager.Penumbra.SetManipulationDataAsync(Logger, _applicationId, penumbraCollection, charaData.ManipulationData).ConfigureAwait(false); + } + + token.ThrowIfCancellationRequested(); + + foreach (var kind in updatedData) + { + await ApplyCustomizationDataAsync(_applicationId, kind, charaData, token).ConfigureAwait(false); + token.ThrowIfCancellationRequested(); + } + + _cachedData = charaData; + _pairStateCache.Store(Ident, charaData); + if (LastAppliedApproximateVRAMBytes < 0 || LastAppliedApproximateEffectiveVRAMBytes < 0) + { + _playerPerformanceService.ComputeAndAutoPauseOnVRAMUsageThresholds(this, charaData, new List()); + } + if (LastAppliedDataTris < 0) + { + await _playerPerformanceService.CheckTriangleUsageThresholds(this, charaData).ConfigureAwait(false); + } + + Logger.LogDebug("[{applicationId}] Application finished", _applicationId); + } + catch (OperationCanceledException ex) when (ex.CancellationToken == token || token.IsCancellationRequested) + { + Logger.LogDebug("[{applicationId}] Application cancelled via request token for {handler}", _applicationId, GetLogIdentifier()); + MarkApplicationDeferred(charaData); + } + catch (OperationCanceledException ex) + { + MarkApplicationDeferred(charaData); + Logger.LogDebug("[{applicationId}] Application deferred; redraw or apply operation cancelled ({reason}) for {handler}", _applicationId, ex.Message, GetLogIdentifier()); + } + catch (Exception ex) + { + if (ex is AggregateException aggr && aggr.InnerExceptions.Any(e => e is ArgumentNullException)) + { + IsVisible = false; + MarkApplicationDeferred(charaData); + Logger.LogDebug("[{applicationId}] Cancelled, player turned null during application", _applicationId); + } + else + { + Logger.LogWarning(ex, "[{applicationId}] Cancelled", _applicationId); + } + } + } + + private void FrameworkUpdate() + { + if (string.IsNullOrEmpty(PlayerName)) + { + var pc = _dalamudUtil.FindPlayerByNameHash(Ident); + if (pc == default((string, nint))) return; + Logger.LogDebug("One-Time Initializing {handler}", GetLogIdentifier()); + Initialize(pc.Name); + Logger.LogDebug("One-Time Initialized {handler}", GetLogIdentifier()); + Mediator.Publish(new EventMessage(new Event(PlayerName, GetPrimaryUserData(), nameof(PairHandlerAdapter), EventSeverity.Informational, + $"Initializing User For Character {pc.Name}"))); + } + + if (_charaHandler?.Address != nint.Zero && !IsVisible && !_pauseRequested) + { + Guid appData = Guid.NewGuid(); + IsVisible = true; + if (_cachedData is not null) + { + var cachedData = _cachedData; + Logger.LogTrace("[BASE-{appBase}] {handler} visibility changed, now: {visi}, cached data exists", appData, GetLogIdentifier(), IsVisible); + + _ = Task.Run(() => + { + try + { + ApplyCharacterData(appData, cachedData!, forceApplyCustomization: true); + } + catch (Exception ex) + { + Logger.LogError(ex, "[BASE-{appBase}] Failed to apply cached character data for {handler}", appData, GetLogIdentifier()); + } + }); + } + else if (LastReceivedCharacterData is not null) + { + Logger.LogTrace("[BASE-{appBase}] {handler} visibility changed, now: {visi}, last received data exists", appData, GetLogIdentifier(), IsVisible); + + _ = Task.Run(() => + { + try + { + ApplyLastReceivedData(forced: true); + } + catch (Exception ex) + { + Logger.LogError(ex, "[BASE-{appBase}] Failed to reapply last received data for {handler}", appData, GetLogIdentifier()); + } + }); + } + else + { + Logger.LogTrace("{handler} visibility changed, now: {visi}, no cached or received data exists", GetLogIdentifier(), IsVisible); + EnsureRestoredStateWhileWaitingForData("VisibleWithoutCachedData"); + } + } + else if (_charaHandler?.Address == nint.Zero && IsVisible) + { + IsVisible = false; + _charaHandler.Invalidate(); + _downloadCancellationTokenSource?.CancelDispose(); + _downloadCancellationTokenSource = null; + Logger.LogTrace("{handler} visibility changed, now: {visi}", GetLogIdentifier(), IsVisible); + } + + TryApplyQueuedData(); + } + + private void Initialize(string name) + { + PlayerName = name; + _charaHandler = _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(Ident), isWatched: false).GetAwaiter().GetResult(); + + var user = GetPrimaryUserData(); + if (!string.IsNullOrEmpty(user.UID)) + { + _serverConfigManager.AutoPopulateNoteForUid(user.UID, name); + } + + Mediator.Subscribe(this, async (_) => + { + if (string.IsNullOrEmpty(_cachedData?.HonorificData)) return; + Logger.LogTrace("Reapplying Honorific data for {handler}", GetLogIdentifier()); + await _ipcManager.Honorific.SetTitleAsync(PlayerCharacter, _cachedData.HonorificData).ConfigureAwait(false); + }); + + Mediator.Subscribe(this, async (_) => + { + if (string.IsNullOrEmpty(_cachedData?.PetNamesData)) return; + Logger.LogTrace("Reapplying Pet Names data for {handler}", GetLogIdentifier()); + await _ipcManager.PetNames.SetPlayerData(PlayerCharacter, _cachedData.PetNamesData).ConfigureAwait(false); + }); + } + + private async Task RevertCustomizationDataAsync(ObjectKind objectKind, string name, Guid applicationId, CancellationToken cancelToken) + { + nint address = _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(Ident); + if (address == nint.Zero) return; + + var alias = GetPrimaryAliasOrUid(); + Logger.LogDebug("[{applicationId}] Reverting all Customization for {alias}/{name} {objectKind}", applicationId, alias, name, objectKind); + + if (_customizeIds.TryGetValue(objectKind, out var customizeId)) + { + _customizeIds.Remove(objectKind); + } + + if (objectKind == ObjectKind.Player) + { + using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => address, isWatched: false).ConfigureAwait(false); + tempHandler.CompareNameAndThrow(name); + Logger.LogDebug("[{applicationId}] Restoring Customization and Equipment for {alias}/{name}", applicationId, alias, name); + await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + tempHandler.CompareNameAndThrow(name); + Logger.LogDebug("[{applicationId}] Restoring Heels for {alias}/{name}", applicationId, alias, name); + await _ipcManager.Heels.RestoreOffsetForPlayerAsync(address).ConfigureAwait(false); + tempHandler.CompareNameAndThrow(name); + Logger.LogDebug("[{applicationId}] Restoring C+ for {alias}/{name}", applicationId, alias, name); + await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); + tempHandler.CompareNameAndThrow(name); + Logger.LogDebug("[{applicationId}] Restoring Honorific for {alias}/{name}", applicationId, alias, name); + await _ipcManager.Honorific.ClearTitleAsync(address).ConfigureAwait(false); + Logger.LogDebug("[{applicationId}] Restoring Moodles for {alias}/{name}", applicationId, alias, name); + await _ipcManager.Moodles.RevertStatusAsync(address).ConfigureAwait(false); + Logger.LogDebug("[{applicationId}] Restoring Pet Nicknames for {alias}/{name}", applicationId, alias, name); + await _ipcManager.PetNames.ClearPlayerData(address).ConfigureAwait(false); + } + else if (objectKind == ObjectKind.MinionOrMount) + { + var minionOrMount = await _dalamudUtil.GetMinionOrMountAsync(address).ConfigureAwait(false); + if (minionOrMount != nint.Zero) + { + await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); + using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => minionOrMount, isWatched: false).ConfigureAwait(false); + await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + await _ipcManager.Penumbra.RedrawAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + } + } + else if (objectKind == ObjectKind.Pet) + { + var pet = await _dalamudUtil.GetPetAsync(address).ConfigureAwait(false); + if (pet != nint.Zero) + { + await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); + using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => pet, isWatched: false).ConfigureAwait(false); + await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + await _ipcManager.Penumbra.RedrawAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + } + } + else if (objectKind == ObjectKind.Companion) + { + var companion = await _dalamudUtil.GetCompanionAsync(address).ConfigureAwait(false); + if (companion != nint.Zero) + { + await _ipcManager.CustomizePlus.RevertByIdAsync(customizeId).ConfigureAwait(false); + using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Pet, () => companion, isWatched: false).ConfigureAwait(false); + await _ipcManager.Glamourer.RevertAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + await _ipcManager.Penumbra.RedrawAsync(Logger, tempHandler, applicationId, cancelToken).ConfigureAwait(false); + } + } + } + + private List TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary<(string GamePath, string? Hash), string> moddedDictionary, CancellationToken token) + { + Stopwatch st = Stopwatch.StartNew(); + ConcurrentBag missingFiles = []; + moddedDictionary = []; + ConcurrentDictionary<(string GamePath, string? Hash), string> outputDict = new(); + bool hasMigrationChanges = false; + bool skipDownscaleForPair = ShouldSkipDownscale(); + + try + { + var replacementList = charaData.FileReplacements.SelectMany(k => k.Value.Where(v => string.IsNullOrEmpty(v.FileSwapPath))).ToList(); + Parallel.ForEach(replacementList, new ParallelOptions() + { + CancellationToken = token, + MaxDegreeOfParallelism = 4 + }, + (item) => + { + token.ThrowIfCancellationRequested(); + var fileCache = _fileDbManager.GetFileCacheByHash(item.Hash); + if (fileCache != null) + { + if (!File.Exists(fileCache.ResolvedFilepath)) + { + Logger.LogTrace("[BASE-{appBase}] Cached path {Path} missing on disk for hash {Hash}, removing cache entry", applicationBase, fileCache.ResolvedFilepath, item.Hash); + _fileDbManager.RemoveHashedFile(fileCache.Hash, fileCache.PrefixedFilePath); + fileCache = null; + } + } + + if (fileCache != null) + { + if (string.IsNullOrEmpty(new FileInfo(fileCache.ResolvedFilepath).Extension)) + { + hasMigrationChanges = true; + fileCache = _fileDbManager.MigrateFileHashToExtension(fileCache, item.GamePaths[0].Split(".")[^1]); + } + + foreach (var gamePath in item.GamePaths) + { + var preferredPath = skipDownscaleForPair + ? fileCache.ResolvedFilepath + : _textureDownscaleService.GetPreferredPath(item.Hash, fileCache.ResolvedFilepath); + outputDict[(gamePath, item.Hash)] = preferredPath; + } + } + else + { + Logger.LogTrace("Missing file: {hash}", item.Hash); + missingFiles.Add(item); + } + }); + + moddedDictionary = outputDict.ToDictionary(k => k.Key, k => k.Value); + + foreach (var item in charaData.FileReplacements.SelectMany(k => k.Value.Where(v => !string.IsNullOrEmpty(v.FileSwapPath))).ToList()) + { + foreach (var gamePath in item.GamePaths) + { + Logger.LogTrace("[BASE-{appBase}] Adding file swap for {path}: {fileSwap}", applicationBase, gamePath, item.FileSwapPath); + moddedDictionary[(gamePath, null)] = item.FileSwapPath; + } + } + } + catch (OperationCanceledException) + { + Logger.LogTrace("[BASE-{appBase}] Modded path calculation cancelled", applicationBase); + throw; + } + catch (Exception ex) + { + Logger.LogError(ex, "[BASE-{appBase}] Something went wrong during calculation replacements", applicationBase); + } + if (hasMigrationChanges) _fileDbManager.WriteOutFullCsv(); + st.Stop(); + Logger.LogDebug("[BASE-{appBase}] ModdedPaths calculated in {time}ms, missing files: {count}, total files: {total}", applicationBase, st.ElapsedMilliseconds, missingFiles.Count, moddedDictionary.Keys.Count); + return [.. missingFiles]; + } + + private async Task PauseInternalAsync() + { + try + { + Logger.LogDebug("Pausing handler {handler}", GetLogIdentifier()); + DisableSync(); + + if (_charaHandler is null || _charaHandler.Address == nint.Zero) + { + IsVisible = false; + return; + } + + var applicationId = Guid.NewGuid(); + await RevertToRestoredAsync(applicationId).ConfigureAwait(false); + IsVisible = false; + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Failed to pause handler {handler}", GetLogIdentifier()); + } + } + + private async Task ResumeInternalAsync() + { + try + { + Logger.LogDebug("Resuming handler {handler}", GetLogIdentifier()); + if (_charaHandler is null || _charaHandler.Address == nint.Zero) + { + return; + } + + if (!IsVisible) + { + IsVisible = true; + } + + if (LastReceivedCharacterData is not null) + { + ApplyLastReceivedData(forced: true); + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Failed to resume handler {handler}", GetLogIdentifier()); + } + } + + private async Task RevertToRestoredAsync(Guid applicationId) + { + if (_charaHandler is null || _charaHandler.Address == nint.Zero) + { + return; + } + + try + { + var gameObject = await _dalamudUtil.RunOnFrameworkThread(() => _charaHandler.GetGameObject()).ConfigureAwait(false); + if (gameObject is not Dalamud.Game.ClientState.Objects.Types.ICharacter character) + { + return; + } + + if (_ipcManager.Penumbra.APIAvailable) + { + var penumbraCollection = EnsurePenumbraCollection(); + if (penumbraCollection != Guid.Empty) + { + await _ipcManager.Penumbra.AssignTemporaryCollectionAsync(Logger, penumbraCollection, character.ObjectIndex).ConfigureAwait(false); + await _ipcManager.Penumbra.SetTemporaryModsAsync(Logger, applicationId, penumbraCollection, new Dictionary()).ConfigureAwait(false); + await _ipcManager.Penumbra.SetManipulationDataAsync(Logger, applicationId, penumbraCollection, string.Empty).ConfigureAwait(false); + } + } + + var kinds = new HashSet(_customizeIds.Keys); + if (_cachedData is not null) + { + foreach (var kind in _cachedData.FileReplacements.Keys) + { + kinds.Add(kind); + } + } + + kinds.Add(ObjectKind.Player); + + var characterName = character.Name.TextValue; + if (string.IsNullOrEmpty(characterName)) + { + characterName = character.Name.ToString(); + } + if (string.IsNullOrEmpty(characterName)) + { + Logger.LogWarning("[{applicationId}] Failed to determine character name for {handler} while reverting", applicationId, GetLogIdentifier()); + return; + } + + foreach (var kind in kinds) + { + await RevertCustomizationDataAsync(kind, characterName, applicationId, CancellationToken.None).ConfigureAwait(false); + } + + _cachedData = null; + LastAppliedDataBytes = -1; + LastAppliedDataTris = -1; + LastAppliedApproximateVRAMBytes = -1; + LastAppliedApproximateEffectiveVRAMBytes = -1; + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Failed to revert handler {handler} during pause", GetLogIdentifier()); + } + } + + private void DisableSync() + { + _downloadCancellationTokenSource = _downloadCancellationTokenSource?.CancelRecreate(); + _applicationCancellationTokenSource = _applicationCancellationTokenSource?.CancelRecreate(); + } + + private void EnableSync() + { + TryApplyQueuedData(); + } + + private void TryApplyQueuedData() + { + var pending = _dataReceivedInDowntime; + if (pending is null || !IsVisible) + { + return; + } + + if (!CanApplyNow()) + { + return; + } + + _dataReceivedInDowntime = null; + ApplyCharacterData(pending.ApplicationId, + pending.CharacterData, pending.Forced); + } + + private void MarkApplicationDeferred(CharacterData charaData) + { + _forceApplyMods = true; + _forceFullReapply = true; + _currentDownloadOwnerToken = Guid.Empty; + _cachedData = charaData; + _pairStateCache.Store(Ident, charaData); + EnqueueDeferredCharacterData(charaData); + } + + private void EnqueueDeferredCharacterData(CharacterData charaData, bool forced = true) + { + try + { + _dataReceivedInDowntime = new(Guid.NewGuid(), charaData.DeepClone(), forced); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to queue deferred data for {handler}", GetLogIdentifier()); + } + } +} + +internal sealed class PairHandlerAdapterFactory : IPairHandlerAdapterFactory +{ + private readonly ILoggerFactory _loggerFactory; + private readonly LightlessMediator _mediator; + private readonly PairManager _pairManager; + private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; + private readonly IpcManager _ipcManager; + private readonly FileDownloadManagerFactory _fileDownloadManagerFactory; + private readonly PluginWarningNotificationService _pluginWarningNotificationManager; + private readonly IServiceProvider _serviceProvider; + private readonly IHostApplicationLifetime _lifetime; + private readonly FileCacheManager _fileCacheManager; + private readonly PlayerPerformanceService _playerPerformanceService; + private readonly PairProcessingLimiter _pairProcessingLimiter; + private readonly ServerConfigurationManager _serverConfigManager; + private readonly TextureDownscaleService _textureDownscaleService; + private readonly PairStateCache _pairStateCache; + + public PairHandlerAdapterFactory( + ILoggerFactory loggerFactory, + LightlessMediator mediator, + PairManager pairManager, + GameObjectHandlerFactory gameObjectHandlerFactory, + IpcManager ipcManager, + FileDownloadManagerFactory fileDownloadManagerFactory, + PluginWarningNotificationService pluginWarningNotificationManager, + IServiceProvider serviceProvider, + IHostApplicationLifetime lifetime, + FileCacheManager fileCacheManager, + PlayerPerformanceService playerPerformanceService, + PairProcessingLimiter pairProcessingLimiter, + ServerConfigurationManager serverConfigManager, + TextureDownscaleService textureDownscaleService, + PairStateCache pairStateCache) + { + _loggerFactory = loggerFactory; + _mediator = mediator; + _pairManager = pairManager; + _gameObjectHandlerFactory = gameObjectHandlerFactory; + _ipcManager = ipcManager; + _fileDownloadManagerFactory = fileDownloadManagerFactory; + _pluginWarningNotificationManager = pluginWarningNotificationManager; + _serviceProvider = serviceProvider; + _lifetime = lifetime; + _fileCacheManager = fileCacheManager; + _playerPerformanceService = playerPerformanceService; + _pairProcessingLimiter = pairProcessingLimiter; + _serverConfigManager = serverConfigManager; + _textureDownscaleService = textureDownscaleService; + _pairStateCache = pairStateCache; + } + + public IPairHandlerAdapter Create(string ident) + { + var downloadManager = _fileDownloadManagerFactory.Create(); + var dalamudUtilService = _serviceProvider.GetRequiredService(); + return new PairHandlerAdapter( + _loggerFactory.CreateLogger(), + _mediator, + _pairManager, + ident, + _gameObjectHandlerFactory, + _ipcManager, + downloadManager, + _pluginWarningNotificationManager, + dalamudUtilService, + _lifetime, + _fileCacheManager, + _playerPerformanceService, + _pairProcessingLimiter, + _serverConfigManager, + _textureDownscaleService, + _pairStateCache); + } +} diff --git a/LightlessSync/PlayerData/Pairs/PairHandlerRegistry.cs b/LightlessSync/PlayerData/Pairs/PairHandlerRegistry.cs new file mode 100644 index 0000000..6c43119 --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/PairHandlerRegistry.cs @@ -0,0 +1,493 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Data.Extensions; +using LightlessSync.API.Dto.CharaData; +using LightlessSync.API.Dto.User; +using Microsoft.Extensions.Logging; + +namespace LightlessSync.PlayerData.Pairs; + +public sealed class PairHandlerRegistry : IDisposable +{ + private readonly object _gate = new(); + private readonly Dictionary _identToHandler = new(StringComparer.Ordinal); + private readonly Dictionary> _handlerToPairs = new(); + private readonly Dictionary _waitingRequests = new(StringComparer.Ordinal); + + private readonly IPairHandlerAdapterFactory _handlerFactory; + private readonly PairManager _pairManager; + private readonly PairStateCache _pairStateCache; + private readonly ILogger _logger; + + private readonly TimeSpan _deletionGracePeriod = TimeSpan.FromMinutes(5); + private readonly TimeSpan _waitForHandlerGracePeriod = TimeSpan.FromMinutes(2); + + public PairHandlerRegistry( + IPairHandlerAdapterFactory handlerFactory, + PairManager pairManager, + PairStateCache pairStateCache, + ILogger logger) + { + _handlerFactory = handlerFactory; + _pairManager = pairManager; + _pairStateCache = pairStateCache; + _logger = logger; + } + + public int GetVisibleUsersCount() + { + lock (_gate) + { + return _handlerToPairs.Keys.Count(handler => handler.IsVisible); + } + } + + public bool IsIdentVisible(string ident) + { + lock (_gate) + { + return _identToHandler.TryGetValue(ident, out var handler) && handler.IsVisible; + } + } + + public PairOperationResult RegisterOnlinePair(PairRegistration registration) + { + if (registration.CharacterIdent is null) + { + return PairOperationResult.Fail($"Registration for {registration.PairIdent.UserId} missing ident."); + } + + IPairHandlerAdapter handler; + lock (_gate) + { + handler = GetOrAddHandler(registration.CharacterIdent); + handler.ScheduledForDeletion = false; + + if (!_handlerToPairs.TryGetValue(handler, out var set)) + { + set = new HashSet(); + _handlerToPairs[handler] = set; + } + + set.Add(registration.PairIdent); + } + + ApplyPauseStateForHandler(handler); + + if (handler.LastReceivedCharacterData is null) + { + var cachedData = _pairStateCache.TryLoad(registration.CharacterIdent); + if (cachedData is not null) + { + handler.LoadCachedCharacterData(cachedData); + } + } + + if (handler.LastReceivedCharacterData is not null && + (handler.LastAppliedApproximateVRAMBytes < 0 || handler.LastAppliedDataTris < 0)) + { + handler.ApplyLastReceivedData(forced: true); + } + + return PairOperationResult.Ok(registration.PairIdent); + } + + public PairOperationResult DeregisterOfflinePair(PairRegistration registration, bool forceDisposal = false) + { + if (registration.CharacterIdent is null) + { + return PairOperationResult.Fail($"Deregister for {registration.PairIdent.UserId} missing ident."); + } + + IPairHandlerAdapter? handler = null; + bool shouldScheduleRemoval = false; + bool shouldDisposeImmediately = false; + + lock (_gate) + { + if (!_identToHandler.TryGetValue(registration.CharacterIdent, out handler)) + { + return PairOperationResult.Fail($"Ident {registration.CharacterIdent} not registered."); + } + + if (_handlerToPairs.TryGetValue(handler, out var set)) + { + set.Remove(registration.PairIdent); + if (set.Count == 0) + { + if (forceDisposal) + { + shouldDisposeImmediately = true; + } + else + { + shouldScheduleRemoval = true; + handler.ScheduledForDeletion = true; + } + } + } + } + + if (shouldDisposeImmediately && handler is not null) + { + if (TryFinalizeHandlerRemoval(handler)) + { + handler.Dispose(); + } + } + else if (shouldScheduleRemoval && handler is not null) + { + _ = RemoveAfterGracePeriodAsync(handler); + } + + return PairOperationResult.Ok(registration.PairIdent); + } + + public PairOperationResult ApplyCharacterData(PairRegistration registration, OnlineUserCharaDataDto dto) + { + if (registration.CharacterIdent is null) + { + return PairOperationResult.Fail($"Character data received without ident for {registration.PairIdent.UserId}."); + } + + IPairHandlerAdapter? handler; + lock (_gate) + { + _identToHandler.TryGetValue(registration.CharacterIdent, out handler); + } + + if (handler is null) + { + var registerResult = RegisterOnlinePair(registration); + if (!registerResult.Success) + { + return PairOperationResult.Fail(registerResult.Error); + } + + lock (_gate) + { + _identToHandler.TryGetValue(registration.CharacterIdent, out handler); + } + } + + if (handler is null) + { + return PairOperationResult.Fail($"Handler not ready for {registration.PairIdent.UserId}."); + } + + handler.ApplyData(dto.CharaData); + return PairOperationResult.Ok(); + } + + public PairOperationResult ApplyLastReceivedData(PairUniqueIdentifier pairIdent, string ident, bool forced = false) + { + IPairHandlerAdapter? handler; + lock (_gate) + { + _identToHandler.TryGetValue(ident, out handler); + } + + if (handler is null) + { + return PairOperationResult.Fail($"Cannot reapply data: handler for {pairIdent.UserId} not found."); + } + + handler.ApplyLastReceivedData(forced); + return PairOperationResult.Ok(); + } + + public PairOperationResult SetUploading(PairUniqueIdentifier pairIdent, string ident, bool uploading) + { + IPairHandlerAdapter? handler; + lock (_gate) + { + _identToHandler.TryGetValue(ident, out handler); + } + + if (handler is null) + { + return PairOperationResult.Fail($"Cannot set uploading for {pairIdent.UserId}: handler not found."); + } + + handler.SetUploading(uploading); + return PairOperationResult.Ok(); + } + + public PairOperationResult SetPausedState(PairUniqueIdentifier pairIdent, string ident, bool paused) + { + IPairHandlerAdapter? handler; + lock (_gate) + { + _identToHandler.TryGetValue(ident, out handler); + } + + if (handler is null) + { + return PairOperationResult.Fail($"Cannot update pause state for {pairIdent.UserId}: handler not found."); + } + + _ = paused; // value reflected in pair manager already + // Recalculate pause state against all registered pairs to ensure consistency across contexts. + ApplyPauseStateForHandler(handler); + return PairOperationResult.Ok(); + } + + public PairOperationResult> GetPairConnections(string ident) + { + IPairHandlerAdapter? handler; + HashSet? identifiers = null; + + lock (_gate) + { + _identToHandler.TryGetValue(ident, out handler); + if (handler is not null) + { + _handlerToPairs.TryGetValue(handler, out identifiers); + } + } + + if (handler is null || identifiers is null) + { + return PairOperationResult>.Fail($"No handler registered for {ident}."); + } + + var list = new List<(PairUniqueIdentifier, PairConnection)>(); + foreach (var pairIdent in identifiers) + { + var result = _pairManager.GetPair(pairIdent.UserId); + if (result.Success) + { + list.Add((pairIdent, result.Value)); + } + } + + return PairOperationResult>.Ok(list); + } + + private void ApplyPauseStateForHandler(IPairHandlerAdapter handler) + { + var pairs = _pairManager.GetPairsByIdent(handler.Ident); + bool paused = pairs.Any(p => p.SelfToOtherPermissions.IsPaused() || p.OtherToSelfPermissions.IsPaused()); + handler.SetPaused(paused); + } + + internal bool TryGetHandler(string ident, out IPairHandlerAdapter? handler) + { + lock (_gate) + { + var success = _identToHandler.TryGetValue(ident, out var resolved); + handler = resolved; + return success; + } + } + + internal IReadOnlyList GetHandlerSnapshot() + { + lock (_gate) + { + return _identToHandler.Values.Distinct().ToList(); + } + } + + internal IReadOnlyCollection GetRegisteredPairs(IPairHandlerAdapter handler) + { + lock (_gate) + { + if (_handlerToPairs.TryGetValue(handler, out var pairs)) + { + return pairs.ToList(); + } + } + + return Array.Empty(); + } + + internal void ReapplyAll(bool forced = false) + { + var handlers = GetHandlerSnapshot(); + foreach (var handler in handlers) + { + try + { + handler.ApplyLastReceivedData(forced); + } + catch (Exception ex) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug(ex, "Failed to reapply cached data for {Ident}", handler.Ident); + } + } + } + } + + internal void ResetAllHandlers() + { + List handlers; + lock (_gate) + { + handlers = _identToHandler.Values.Distinct().ToList(); + _identToHandler.Clear(); + _handlerToPairs.Clear(); + + foreach (var pending in _waitingRequests.Values) + { + pending.Cancel(); + pending.Dispose(); + } + + _waitingRequests.Clear(); + } + + foreach (var handler in handlers) + { + try + { + handler.Dispose(); + } + catch (Exception ex) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug(ex, "Failed to dispose handler for {Ident}", handler.Ident); + } + } + } + } + + public void Dispose() + { + List handlers; + lock (_gate) + { + handlers = _identToHandler.Values.Distinct().ToList(); + _identToHandler.Clear(); + _handlerToPairs.Clear(); + foreach (var kv in _waitingRequests.Values) + { + kv.Cancel(); + } + _waitingRequests.Clear(); + } + + foreach (var handler in handlers) + { + handler.Dispose(); + } + } + + private IPairHandlerAdapter GetOrAddHandler(string ident) + { + if (_identToHandler.TryGetValue(ident, out var handler)) + { + return handler; + } + + handler = _handlerFactory.Create(ident); + _identToHandler[ident] = handler; + _handlerToPairs[handler] = new HashSet(); + return handler; + } + + private void EnsureInitialized(IPairHandlerAdapter handler) + { + if (handler.Initialized) + { + return; + } + + try + { + handler.Initialize(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to initialize handler for {Ident}", handler.Ident); + } + } + + private async Task RemoveAfterGracePeriodAsync(IPairHandlerAdapter handler) + { + try + { + await Task.Delay(_deletionGracePeriod).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + return; + } + + if (TryFinalizeHandlerRemoval(handler)) + { + handler.Dispose(); + } + } + + private bool TryFinalizeHandlerRemoval(IPairHandlerAdapter handler) + { + lock (_gate) + { + if (!_handlerToPairs.TryGetValue(handler, out var set) || set.Count > 0) + { + handler.ScheduledForDeletion = false; + return false; + } + + _handlerToPairs.Remove(handler); + _identToHandler.Remove(handler.Ident); + + if (_waitingRequests.TryGetValue(handler.Ident, out var cts)) + { + cts.Cancel(); + cts.Dispose(); + _waitingRequests.Remove(handler.Ident); + } + + return true; + } + } + + private async Task WaitThenApplyDataAsync(PairRegistration registration, OnlineUserCharaDataDto dto, CancellationTokenSource cts) + { + var token = cts.Token; + try + { + while (!token.IsCancellationRequested) + { + IPairHandlerAdapter? handler; + lock (_gate) + { + _identToHandler.TryGetValue(registration.CharacterIdent!, out handler); + } + + if (handler is not null && handler.Initialized) + { + handler.ApplyData(dto.CharaData); + break; + } + + await Task.Delay(TimeSpan.FromMilliseconds(500), token).ConfigureAwait(false); + } + } + catch (OperationCanceledException) + { + // expected + } + finally + { + lock (_gate) + { + if (_waitingRequests.TryGetValue(registration.CharacterIdent!, out var existing) && existing == cts) + { + _waitingRequests.Remove(registration.CharacterIdent!); + } + } + + cts.Dispose(); + } + } +} diff --git a/LightlessSync/PlayerData/Pairs/PairLedger.cs b/LightlessSync/PlayerData/Pairs/PairLedger.cs new file mode 100644 index 0000000..1e0e359 --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/PairLedger.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LightlessSync.API.Data; +using LightlessSync.API.Dto.Group; +using LightlessSync.Services.Events; +using LightlessSync.Services.Mediator; +using LightlessSync.UI.Models; +using Microsoft.Extensions.Logging; + +namespace LightlessSync.PlayerData.Pairs; + +public sealed class PairLedger : DisposableMediatorSubscriberBase +{ + private readonly PairManager _pairManager; + private readonly PairHandlerRegistry _registry; + private readonly ILogger _logger; + private readonly object _metricsGate = new(); + private CancellationTokenSource? _ensureMetricsCts; + + public PairLedger( + ILogger logger, + LightlessMediator mediator, + PairManager pairManager, + PairHandlerRegistry registry) : base(logger, mediator) + { + _pairManager = pairManager; + _registry = registry; + _logger = logger; + + Mediator.Subscribe(this, _ => ReapplyAll(forced: true)); + Mediator.Subscribe(this, _ => ReapplyAll()); + Mediator.Subscribe(this, _ => ReapplyAll(forced: true)); + Mediator.Subscribe(this, _ => ReapplyAll(forced: true)); + Mediator.Subscribe(this, _ => Reset()); + Mediator.Subscribe(this, _ => ScheduleEnsureMetrics(TimeSpan.FromSeconds(2))); + Mediator.Subscribe(this, _ => ScheduleEnsureMetrics(TimeSpan.FromSeconds(2))); + Mediator.Subscribe(this, _ => ScheduleEnsureMetrics(TimeSpan.FromSeconds(2))); + Mediator.Subscribe(this, _ => EnsureMetricsForVisiblePairs()); + } + + public bool IsPairVisible(PairUniqueIdentifier pairIdent) + { + var connectionResult = _pairManager.GetPair(pairIdent.UserId); + if (!connectionResult.Success) + { + return false; + } + + var connection = connectionResult.Value; + if (connection.Ident is null) + { + return false; + } + + return _registry.IsIdentVisible(connection.Ident); + } + + public IPairHandlerAdapter? GetHandler(PairUniqueIdentifier pairIdent) + { + var connectionResult = _pairManager.GetPair(pairIdent.UserId); + if (!connectionResult.Success) + { + return null; + } + + var connection = connectionResult.Value; + if (connection.Ident is null) + { + return null; + } + + return _registry.TryGetHandler(connection.Ident, out var handler) ? handler : null; + } + + public IReadOnlyList GetVisiblePairs() + { + return _pairManager.GetAllPairs() + .Select(kv => kv.Value) + .Where(connection => connection.Ident is not null && _registry.IsIdentVisible(connection.Ident)) + .ToList(); + } + + public IReadOnlyList GetAllGroupInfos() + { + return _pairManager.GetAllGroups() + .Select(kv => kv.Value.GroupFullInfo) + .ToList(); + } + + public IReadOnlyDictionary GetAllSyncshells() + { + return _pairManager.GetAllGroups(); + } + + public void ReapplyAll(bool forced = false) + { + if (_logger.IsEnabled(LogLevel.Trace)) + { + _logger.LogTrace("Reapplying cached data for all handlers (forced: {Forced})", forced); + } + + _registry.ReapplyAll(forced); + } + + public void ReapplyPair(PairUniqueIdentifier pairIdent, bool forced = false) + { + var connectionResult = _pairManager.GetPair(pairIdent.UserId); + if (!connectionResult.Success) + { + return; + } + + var connection = connectionResult.Value; + if (connection.Ident is null) + { + return; + } + + var result = _registry.ApplyLastReceivedData(pairIdent, connection.Ident, forced); + if (!result.Success && _logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Failed to reapply data for {UserId}: {Error}", pairIdent.UserId, result.Error); + } + } + + private void Reset() + { + if (_logger.IsEnabled(LogLevel.Trace)) + { + _logger.LogTrace("Resetting pair handlers after disconnect."); + } + + CancelScheduledMetrics(); + } + + public IReadOnlyList GetAllEntries() + { + var groups = _pairManager.GetAllGroups(); + var list = new List(); + foreach (var (userId, connection) in _pairManager.GetAllPairs()) + { + var ident = new PairUniqueIdentifier(userId); + IPairHandlerAdapter? handler = null; + if (connection.Ident is not null) + { + _registry.TryGetHandler(connection.Ident, out handler); + } + + var groupInfos = connection.Groups.Keys + .Select(gid => + { + if (groups.TryGetValue(gid, out var shell)) + { + return shell.GroupFullInfo; + } + return null; + }) + .Where(dto => dto is not null) + .Cast() + .ToList(); + + list.Add(new PairDisplayEntry(ident, connection, groupInfos, handler)); + } + + return list; + } + + public bool TryGetEntry(PairUniqueIdentifier ident, out PairDisplayEntry? entry) + { + entry = null; + var connectionResult = _pairManager.GetPair(ident.UserId); + if (!connectionResult.Success) + { + return false; + } + + var connection = connectionResult.Value; + var groups = connection.Groups.Keys + .Select(gid => + { + var groupResult = _pairManager.GetGroup(gid); + return groupResult.Success ? groupResult.Value.GroupFullInfo : null; + }) + .Where(dto => dto is not null) + .Cast() + .ToList(); + + IPairHandlerAdapter? handler = null; + if (connection.Ident is not null) + { + _registry.TryGetHandler(connection.Ident, out handler); + } + + entry = new PairDisplayEntry(ident, connection, groups, handler); + return true; + } + + private void ScheduleEnsureMetrics(TimeSpan? delay = null) + { + lock (_metricsGate) + { + _ensureMetricsCts?.Cancel(); + var cts = new CancellationTokenSource(); + _ensureMetricsCts = cts; + _ = Task.Run(async () => + { + try + { + if (delay is { } d && d > TimeSpan.Zero) + { + await Task.Delay(d, cts.Token).ConfigureAwait(false); + } + + EnsureMetricsForVisiblePairs(); + } + catch (OperationCanceledException) + { + // ignored + } + finally + { + lock (_metricsGate) + { + if (_ensureMetricsCts == cts) + { + _ensureMetricsCts = null; + } + } + + cts.Dispose(); + } + }); + } + } + + private void CancelScheduledMetrics() + { + lock (_metricsGate) + { + _ensureMetricsCts?.Cancel(); + _ensureMetricsCts = null; + } + } + + private void EnsureMetricsForVisiblePairs() + { + var handlers = _registry.GetHandlerSnapshot(); + foreach (var handler in handlers) + { + if (!handler.IsVisible) + { + continue; + } + + if (handler.LastReceivedCharacterData is null) + { + continue; + } + + if (handler.LastAppliedApproximateVRAMBytes >= 0 + && handler.LastAppliedDataTris >= 0 + && handler.LastAppliedApproximateEffectiveVRAMBytes >= 0) + { + continue; + } + + try + { + handler.ApplyLastReceivedData(forced: true); + } + catch (Exception ex) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug(ex, "Failed to ensure performance metrics for {Ident}", handler.Ident); + } + } + } + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + CancelScheduledMetrics(); + } + + base.Dispose(disposing); + } +} diff --git a/LightlessSync/PlayerData/Pairs/PairManager.cs b/LightlessSync/PlayerData/Pairs/PairManager.cs index 2044db0..adbe5b8 100644 --- a/LightlessSync/PlayerData/Pairs/PairManager.cs +++ b/LightlessSync/PlayerData/Pairs/PairManager.cs @@ -1,497 +1,575 @@ -using Dalamud.Plugin.Services; +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using LightlessSync.API.Data; -using LightlessSync.API.Data.Comparer; -using LightlessSync.API.Data.Extensions; +using LightlessSync.API.Data.Enum; using LightlessSync.API.Dto.Group; using LightlessSync.API.Dto.User; -using LightlessSync.LightlessConfiguration; -using LightlessSync.LightlessConfiguration.Models; -using LightlessSync.PlayerData.Factories; -using LightlessSync.Services; - -using LightlessSync.Services.Events; -using LightlessSync.Services.Mediator; -using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; -using System.Threading; -using System.Threading.Tasks; namespace LightlessSync.PlayerData.Pairs; -public sealed class PairManager : DisposableMediatorSubscriberBase +public sealed class PairManager { - private readonly ConcurrentDictionary _allClientPairs = new(UserDataComparer.Instance); - private readonly ConcurrentDictionary _allGroups = new(GroupDataComparer.Instance); - private readonly LightlessConfigService _configurationService; - private readonly IContextMenu _dalamudContextMenu; - private readonly PairFactory _pairFactory; - private Lazy> _directPairsInternal; - private Lazy>> _groupPairsInternal; - private Lazy>> _pairsWithGroupsInternal; - private readonly PairProcessingLimiter _pairProcessingLimiter; - private readonly ConcurrentQueue<(Pair Pair, OnlineUserIdentDto? Ident)> _pairCreationQueue = new(); - private CancellationTokenSource _pairCreationCts = new(); - private int _pairCreationProcessorRunning; + private readonly object _gate = new(); + private readonly Dictionary _pairs = new(StringComparer.Ordinal); + private readonly Dictionary _groups = new(StringComparer.Ordinal); - public PairManager(ILogger logger, PairFactory pairFactory, - LightlessConfigService configurationService, LightlessMediator mediator, - IContextMenu dalamudContextMenu, PairProcessingLimiter pairProcessingLimiter) : base(logger, mediator) + public PairConnection? LastAddedUser { get; private set; } + + public IReadOnlyDictionary GetAllPairs() { - _pairFactory = pairFactory; - _configurationService = configurationService; - _dalamudContextMenu = dalamudContextMenu; - _pairProcessingLimiter = pairProcessingLimiter; - Mediator.Subscribe(this, (_) => ClearPairs()); - Mediator.Subscribe(this, (_) => ReapplyPairData()); - _directPairsInternal = DirectPairsLazy(); - _groupPairsInternal = GroupPairsLazy(); - _pairsWithGroupsInternal = PairsWithGroupsLazy(); - - _dalamudContextMenu.OnMenuOpened += DalamudContextMenuOnOnOpenGameObjectContextMenu; - } - - public List DirectPairs => _directPairsInternal.Value; - - public Dictionary> GroupPairs => _groupPairsInternal.Value; - public Dictionary Groups => _allGroups.ToDictionary(k => k.Key, k => k.Value); - public Pair? LastAddedUser { get; internal set; } - public Dictionary> PairsWithGroups => _pairsWithGroupsInternal.Value; - - public void AddGroup(GroupFullInfoDto dto) - { - _allGroups[dto.Group] = dto; - RecreateLazy(); - } - - public void AddGroupPair(GroupPairFullInfoDto dto) - { - if (!_allClientPairs.ContainsKey(dto.User)) - _allClientPairs[dto.User] = _pairFactory.Create(new UserFullPairDto(dto.User, API.Data.Enum.IndividualPairStatus.None, - [dto.Group.GID], dto.SelfToOtherPermissions, dto.OtherToSelfPermissions)); - else _allClientPairs[dto.User].UserPair.Groups.Add(dto.GID); - RecreateLazy(); - } - - public Pair? GetPairByUID(string uid) - { - var existingPair = _allClientPairs.FirstOrDefault(f => f.Key.UID == uid); - if (!Equals(existingPair, default(KeyValuePair))) + lock (_gate) { - return existingPair.Value; + return new Dictionary(_pairs); } - - return null; } - public void AddUserPair(UserFullPairDto dto) + public IReadOnlyDictionary GetAllGroups() { - if (!_allClientPairs.ContainsKey(dto.User)) + lock (_gate) { - _allClientPairs[dto.User] = _pairFactory.Create(dto); + return new Dictionary(_groups); } - else - { - _allClientPairs[dto.User].UserPair.IndividualPairStatus = dto.IndividualPairStatus; - _allClientPairs[dto.User].ApplyLastReceivedData(); - } - - RecreateLazy(); } - public void AddUserPair(UserPairDto dto, bool addToLastAddedUser = true) + public PairConnection? GetLastAddedUser() { - if (!_allClientPairs.ContainsKey(dto.User)) + lock (_gate) { - _allClientPairs[dto.User] = _pairFactory.Create(dto); + return LastAddedUser; } - else - { - addToLastAddedUser = false; - } - - _allClientPairs[dto.User].UserPair.IndividualPairStatus = dto.IndividualPairStatus; - _allClientPairs[dto.User].UserPair.OwnPermissions = dto.OwnPermissions; - _allClientPairs[dto.User].UserPair.OtherPermissions = dto.OtherPermissions; - if (addToLastAddedUser) - LastAddedUser = _allClientPairs[dto.User]; - _allClientPairs[dto.User].ApplyLastReceivedData(); - RecreateLazy(); } - public void ClearPairs() + public void ClearLastAddedUser() { - Logger.LogDebug("Clearing all Pairs"); - ResetPairCreationQueue(); - DisposePairs(); - _allClientPairs.Clear(); - _allGroups.Clear(); - RecreateLazy(); - } - - public List GetOnlineUserPairs() => _allClientPairs.Where(p => !string.IsNullOrEmpty(p.Value.GetPlayerNameHash())).Select(p => p.Value).ToList(); - - public int GetVisibleUserCount() => _allClientPairs.Count(p => p.Value.IsVisible); - - public List GetVisibleUsers() => [.. _allClientPairs.Where(p => p.Value.IsVisible).Select(p => p.Key)]; - - public void MarkPairOffline(UserData user) - { - if (_allClientPairs.TryGetValue(user, out var pair)) + lock (_gate) { - Mediator.Publish(new ClearProfileUserDataMessage(pair.UserData)); - pair.MarkOffline(); + LastAddedUser = null; } - - RecreateLazy(); } - public void MarkPairOnline(OnlineUserIdentDto dto, bool sendNotif = true) + public void ClearAll() { - if (!_allClientPairs.ContainsKey(dto.User)) throw new InvalidOperationException("No user found for " + dto); - - Mediator.Publish(new ClearProfileUserDataMessage(dto.User)); - - var pair = _allClientPairs[dto.User]; - if (pair.HasCachedPlayer) + lock (_gate) { - RecreateLazy(); - return; + _pairs.Clear(); + _groups.Clear(); + LastAddedUser = null; } - - if (sendNotif && _configurationService.Current.ShowOnlineNotifications - && (_configurationService.Current.ShowOnlineNotificationsOnlyForIndividualPairs && pair.IsDirectlyPaired && !pair.IsOneSidedPair - || !_configurationService.Current.ShowOnlineNotificationsOnlyForIndividualPairs) - && (_configurationService.Current.ShowOnlineNotificationsOnlyForNamedPairs && !string.IsNullOrEmpty(pair.GetNote()) - || !_configurationService.Current.ShowOnlineNotificationsOnlyForNamedPairs)) - { - string? note = pair.GetNote(); - var msg = !string.IsNullOrEmpty(note) - ? $"{note} ({pair.UserData.AliasOrUID}) is now online" - : $"{pair.UserData.AliasOrUID} is now online"; - Mediator.Publish(new NotificationMessage("User online", msg, NotificationType.Info, TimeSpan.FromSeconds(5))); - } - - QueuePairCreation(pair, dto); - - RecreateLazy(); } - public void ReceiveCharaData(OnlineUserCharaDataDto dto) + public PairOperationResult GetPair(string userId) { - if (!_allClientPairs.TryGetValue(dto.User, out var pair)) throw new InvalidOperationException("No user found for " + dto.User); - - Mediator.Publish(new EventMessage(new Event(pair.UserData, nameof(PairManager), EventSeverity.Informational, "Received Character Data"))); - _allClientPairs[dto.User].ApplyData(dto); - } - - public void RemoveGroup(GroupData data) - { - _allGroups.TryRemove(data, out _); - - foreach (var item in _allClientPairs.ToList()) + lock (_gate) { - item.Value.UserPair.Groups.Remove(data.GID); - - if (!item.Value.HasAnyConnection()) + if (_pairs.TryGetValue(userId, out var connection)) { - item.Value.MarkOffline(); - _allClientPairs.TryRemove(item.Key, out _); - } - } - - RecreateLazy(); - } - - public void RemoveGroupPair(GroupPairDto dto) - { - if (_allClientPairs.TryGetValue(dto.User, out var pair)) - { - pair.UserPair.Groups.Remove(dto.Group.GID); - - if (!pair.HasAnyConnection()) - { - pair.MarkOffline(); - _allClientPairs.TryRemove(dto.User, out _); - } - } - - RecreateLazy(); - } - - public void RemoveUserPair(UserDto dto) - { - if (_allClientPairs.TryGetValue(dto.User, out var pair)) - { - pair.UserPair.IndividualPairStatus = API.Data.Enum.IndividualPairStatus.None; - - if (!pair.HasAnyConnection()) - { - pair.MarkOffline(); - _allClientPairs.TryRemove(dto.User, out _); - } - } - - RecreateLazy(); - } - - public void SetGroupInfo(GroupInfoDto dto) - { - _allGroups[dto.Group].Group = dto.Group; - _allGroups[dto.Group].Owner = dto.Owner; - _allGroups[dto.Group].GroupPermissions = dto.GroupPermissions; - - RecreateLazy(); - } - - public void UpdatePairPermissions(UserPermissionsDto dto) - { - if (!_allClientPairs.TryGetValue(dto.User, out var pair)) - { - throw new InvalidOperationException("No such pair for " + dto); - } - - if (pair.UserPair == null) throw new InvalidOperationException("No direct pair for " + dto); - - if (pair.UserPair.OtherPermissions.IsPaused() != dto.Permissions.IsPaused()) - { - Mediator.Publish(new ClearProfileUserDataMessage(dto.User)); - } - - pair.UserPair.OtherPermissions = dto.Permissions; - - Logger.LogTrace("Paused: {paused}, Anims: {anims}, Sounds: {sounds}, VFX: {vfx}", - pair.UserPair.OtherPermissions.IsPaused(), - pair.UserPair.OtherPermissions.IsDisableAnimations(), - pair.UserPair.OtherPermissions.IsDisableSounds(), - pair.UserPair.OtherPermissions.IsDisableVFX()); - - if (!pair.IsPaused) - pair.ApplyLastReceivedData(); - - RecreateLazy(); - } - - public void UpdateSelfPairPermissions(UserPermissionsDto dto) - { - if (!_allClientPairs.TryGetValue(dto.User, out var pair)) - { - throw new InvalidOperationException("No such pair for " + dto); - } - - if (pair.UserPair.OwnPermissions.IsPaused() != dto.Permissions.IsPaused()) - { - Mediator.Publish(new ClearProfileUserDataMessage(dto.User)); - } - - pair.UserPair.OwnPermissions = dto.Permissions; - - Logger.LogTrace("Paused: {paused}, Anims: {anims}, Sounds: {sounds}, VFX: {vfx}", - pair.UserPair.OwnPermissions.IsPaused(), - pair.UserPair.OwnPermissions.IsDisableAnimations(), - pair.UserPair.OwnPermissions.IsDisableSounds(), - pair.UserPair.OwnPermissions.IsDisableVFX()); - - if (!pair.IsPaused) - pair.ApplyLastReceivedData(); - - RecreateLazy(); - } - - internal void ReceiveUploadStatus(UserDto dto) - { - if (_allClientPairs.TryGetValue(dto.User, out var existingPair) && existingPair.IsVisible) - { - existingPair.SetIsUploading(); - } - } - - internal void SetGroupPairStatusInfo(GroupPairUserInfoDto dto) - { - _allGroups[dto.Group].GroupPairUserInfos[dto.UID] = dto.GroupUserInfo; - RecreateLazy(); - } - - internal void SetGroupPermissions(GroupPermissionDto dto) - { - _allGroups[dto.Group].GroupPermissions = dto.Permissions; - RecreateLazy(); - } - - internal void SetGroupStatusInfo(GroupPairUserInfoDto dto) - { - _allGroups[dto.Group].GroupUserInfo = dto.GroupUserInfo; - RecreateLazy(); - } - - internal void UpdateGroupPairPermissions(GroupPairUserPermissionDto dto) - { - _allGroups[dto.Group].GroupUserPermissions = dto.GroupPairPermissions; - RecreateLazy(); - } - - internal void UpdateIndividualPairStatus(UserIndividualPairStatusDto dto) - { - if (_allClientPairs.TryGetValue(dto.User, out var pair)) - { - pair.UserPair.IndividualPairStatus = dto.IndividualPairStatus; - RecreateLazy(); - } - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - ResetPairCreationQueue(); - _dalamudContextMenu.OnMenuOpened -= DalamudContextMenuOnOnOpenGameObjectContextMenu; - - DisposePairs(); - } - - private void DalamudContextMenuOnOnOpenGameObjectContextMenu(Dalamud.Game.Gui.ContextMenu.IMenuOpenedArgs args) - { - if (args.MenuType == Dalamud.Game.Gui.ContextMenu.ContextMenuType.Inventory) return; - if (!_configurationService.Current.EnableRightClickMenus) return; - - foreach (var pair in _allClientPairs.Where((p => p.Value.IsVisible))) - { - pair.Value.AddContextMenu(args); - } - } - - private Lazy> DirectPairsLazy() => new(() => _allClientPairs.Select(k => k.Value) - .Where(k => k.IndividualPairStatus != API.Data.Enum.IndividualPairStatus.None).ToList()); - - private void DisposePairs() - { - Logger.LogDebug("Disposing all Pairs"); - Parallel.ForEach(_allClientPairs, item => - { - item.Value.MarkOffline(wait: false); - }); - - RecreateLazy(); - } - - private Lazy>> GroupPairsLazy() - { - return new Lazy>>(() => - { - Dictionary> outDict = []; - foreach (var group in _allGroups) - { - outDict[group.Value] = _allClientPairs.Select(p => p.Value).Where(p => p.UserPair.Groups.Exists(g => GroupDataComparer.Instance.Equals(group.Key, new(g)))).ToList(); - } - return outDict; - }); - } - - private Lazy>> PairsWithGroupsLazy() - { - return new Lazy>>(() => - { - Dictionary> outDict = []; - - foreach (var pair in _allClientPairs.Select(k => k.Value)) - { - outDict[pair] = _allGroups.Where(k => pair.UserPair.Groups.Contains(k.Key.GID, StringComparer.Ordinal)).Select(k => k.Value).ToList(); + return PairOperationResult.Ok(connection); } - return outDict; - }); - } - - private void QueuePairCreation(Pair pair, OnlineUserIdentDto? dto) - { - if (pair.HasCachedPlayer) - { - RecreateLazy(); - return; - } - - _pairCreationQueue.Enqueue((pair, dto)); - StartPairCreationProcessor(); - } - - private void StartPairCreationProcessor() - { - if (_pairCreationCts.IsCancellationRequested) - { - return; - } - - if (Interlocked.CompareExchange(ref _pairCreationProcessorRunning, 1, 0) == 0) - { - _ = Task.Run(ProcessPairCreationQueueAsync); + return PairOperationResult.Fail($"Pair {userId} not found."); } } - private async Task ProcessPairCreationQueueAsync() + public bool TryGetPair(string userId, [NotNullWhen(true)] out PairConnection? connection) { - try + lock (_gate) { - while (!_pairCreationCts.IsCancellationRequested) + return _pairs.TryGetValue(userId, out connection); + } + } + + public PairOperationResult GetGroup(string groupId) + { + lock (_gate) + { + if (_groups.TryGetValue(groupId, out var shell)) { - if (!_pairCreationQueue.TryDequeue(out var work)) + return PairOperationResult.Ok(shell); + } + + return PairOperationResult.Fail($"Group {groupId} not found."); + } + } + + public IReadOnlyList GetDirectPairs() + { + lock (_gate) + { + return _pairs.Values.Where(p => p.IsDirectlyPaired).ToList(); + } + } + + public IReadOnlyList GetPairsByIdent(string ident) + { + lock (_gate) + { + return _pairs.Values + .Where(p => p.Ident is not null && string.Equals(p.Ident, ident, StringComparison.Ordinal)) + .ToList(); + } + } + + public IReadOnlyList GetOwnedOrModeratedShells(string currentUserUid) + { + lock (_gate) + { + return _groups.Values + .Where(s => + string.Equals(s.GroupFullInfo.Owner.UID, currentUserUid, StringComparison.OrdinalIgnoreCase) + || s.GroupFullInfo.GroupUserInfo.HasFlag(GroupPairUserInfo.IsModerator)) + .ToList(); + } + } + + public PairOperationResult GetPairCombinedPermissions(string userId) + { + lock (_gate) + { + if (!_pairs.TryGetValue(userId, out var connection)) + { + return PairOperationResult.Fail($"Pair {userId} not found."); + } + + var combined = connection.SelfToOtherPermissions | connection.OtherToSelfPermissions; + return PairOperationResult.Ok(combined); + } + } + + public PairOperationResult MarkOnline(OnlineUserIdentDto dto) + { + lock (_gate) + { + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + connection = GetOrCreatePair(dto.User); + } + + connection.SetOnline(dto.Ident); + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(dto.User.UID), dto.Ident)); + } + } + + public PairOperationResult MarkOffline(UserData user) + { + lock (_gate) + { + if (!_pairs.TryGetValue(user.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {user.UID} not found."); + } + + connection.SetOffline(); + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(user.UID), connection.Ident)); + } + } + + public PairOperationResult AddOrUpdateIndividual(UserPairDto dto, bool markAsLastAddedUser = true) + { + lock (_gate) + { + var connection = GetOrCreatePair(dto.User, out var created); + connection.UpdatePermissions(dto.OwnPermissions, dto.OtherPermissions); + connection.UpdateStatus(dto.IndividualPairStatus == IndividualPairStatus.None ? null : dto.IndividualPairStatus); + + if (connection.Ident is null) + { + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(dto.User.UID), null)); + } + + if (created && markAsLastAddedUser) + { + LastAddedUser = connection; + } + + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(dto.User.UID), connection.Ident)); + } + } + + public PairOperationResult AddOrUpdateIndividual(UserFullPairDto dto) + { + lock (_gate) + { + var connection = GetOrCreatePair(dto.User, out _); + connection.UpdatePermissions(dto.OwnPermissions, dto.OtherPermissions); + connection.UpdateStatus(dto.IndividualPairStatus == IndividualPairStatus.None ? null : dto.IndividualPairStatus); + + var removedGroups = connection.Groups.Keys.Where(k => !dto.Groups.Contains(k, StringComparer.Ordinal)).ToList(); + foreach (var groupId in removedGroups) + { + connection.RemoveGroupRelationship(groupId); + if (_groups.TryGetValue(groupId, out var shell)) { - break; + shell.Users.Remove(dto.User.UID); } - - try - { - await using var lease = await _pairProcessingLimiter.AcquireAsync(_pairCreationCts.Token).ConfigureAwait(false); - if (!work.Pair.HasCachedPlayer) - { - work.Pair.CreateCachedPlayer(work.Ident); - } - } - catch (OperationCanceledException) - { - break; - } - catch (Exception ex) - { - Logger.LogError(ex, "Error creating cached player for {uid}", work.Pair.UserData.UID); - } - - RecreateLazy(); - await Task.Yield(); } - } - finally - { - Interlocked.Exchange(ref _pairCreationProcessorRunning, 0); - if (!_pairCreationQueue.IsEmpty && !_pairCreationCts.IsCancellationRequested) + + foreach (var groupId in dto.Groups) { - StartPairCreationProcessor(); + connection.EnsureGroupRelationship(groupId, null); + if (_groups.TryGetValue(groupId, out var shell)) + { + shell.Users[dto.User.UID] = connection; + } } + + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(dto.User.UID), connection.Ident)); } } - private void ResetPairCreationQueue() + public PairOperationResult RemoveIndividual(UserDto dto) { - _pairCreationCts.Cancel(); - while (_pairCreationQueue.TryDequeue(out _)) + lock (_gate) { + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {dto.User.UID} not found."); + } + + connection.UpdateStatus(null); + var registration = TryRemovePairIfNoConnection(connection); + return PairOperationResult.Ok(registration); } - _pairCreationCts.Dispose(); - _pairCreationCts = new CancellationTokenSource(); - Interlocked.Exchange(ref _pairCreationProcessorRunning, 0); } - private void ReapplyPairData() + public PairOperationResult SetPairOtherToSelfPermissions(UserPermissionsDto dto) { - foreach (var pair in _allClientPairs.Select(k => k.Value)) + lock (_gate) { - pair.ApplyLastReceivedData(forced: true); + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {dto.User.UID} not found."); + } + + connection.UpdatePermissions(connection.SelfToOtherPermissions, dto.Permissions); + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(dto.User.UID), connection.Ident)); } } - private void RecreateLazy() + public PairOperationResult SetPairSelfToOtherPermissions(UserPermissionsDto dto) { - _directPairsInternal = DirectPairsLazy(); - _groupPairsInternal = GroupPairsLazy(); - _pairsWithGroupsInternal = PairsWithGroupsLazy(); - Mediator.Publish(new RefreshUiMessage()); + lock (_gate) + { + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {dto.User.UID} not found."); + } + + connection.UpdatePermissions(dto.Permissions, connection.OtherToSelfPermissions); + return PairOperationResult.Ok(new PairRegistration(new PairUniqueIdentifier(dto.User.UID), connection.Ident)); + } } -} \ No newline at end of file + + public PairOperationResult SetIndividualStatus(UserIndividualPairStatusDto dto) + { + lock (_gate) + { + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {dto.User.UID} not found."); + } + + connection.UpdateStatus(dto.IndividualPairStatus == IndividualPairStatus.None ? null : dto.IndividualPairStatus); + _ = TryRemovePairIfNoConnection(connection); + return PairOperationResult.Ok(); + } + } + + public PairOperationResult AddOrUpdateGroupPair(GroupPairFullInfoDto dto) + { + lock (_gate) + { + var shell = GetOrCreateShell(dto.Group); + var connection = GetOrCreatePair(dto.User); + + var groupInfo = shell.GroupFullInfo.GroupPairUserInfos.GetValueOrDefault(dto.User.UID, GroupPairUserInfo.None); + connection.EnsureGroupRelationship(dto.Group.GID, groupInfo == GroupPairUserInfo.None ? null : groupInfo); + connection.UpdatePermissions(dto.SelfToOtherPermissions, dto.OtherToSelfPermissions); + + shell.Users[dto.User.UID] = connection; + return PairOperationResult.Ok(); + } + } + + public PairOperationResult RemoveGroupPair(GroupPairDto dto) + { + lock (_gate) + { + if (_groups.TryGetValue(dto.GID, out var shell)) + { + shell.Users.Remove(dto.User.UID); + } + + PairRegistration? registration = null; + if (_pairs.TryGetValue(dto.User.UID, out var connection)) + { + connection.RemoveGroupRelationship(dto.GID); + registration = TryRemovePairIfNoConnection(connection); + } + + return PairOperationResult.Ok(registration); + } + } + + public PairOperationResult> RemoveGroup(string groupId) + { + lock (_gate) + { + if (!_groups.Remove(groupId, out var shell)) + { + return PairOperationResult>.Fail($"Group {groupId} not found."); + } + + var removed = new List(); + foreach (var connection in shell.Users.Values.ToList()) + { + connection.RemoveGroupRelationship(groupId); + var registration = TryRemovePairIfNoConnection(connection); + if (registration is not null) + { + removed.Add(registration); + } + } + + return PairOperationResult>.Ok(removed); + } + } + + public PairOperationResult AddGroup(GroupFullInfoDto dto) + { + lock (_gate) + { + if (!_groups.TryGetValue(dto.Group.GID, out var shell)) + { + shell = new Syncshell(dto); + _groups[dto.Group.GID] = shell; + } + else + { + shell.Update(dto); + shell.Users.Clear(); + } + + foreach (var (userId, info) in dto.GroupPairUserInfos) + { + if (_pairs.TryGetValue(userId, out var connection)) + { + connection.EnsureGroupRelationship(dto.Group.GID, info == GroupPairUserInfo.None ? null : info); + shell.Users[userId] = connection; + } + } + + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateGroupInfo(GroupInfoDto dto) + { + lock (_gate) + { + if (!_groups.TryGetValue(dto.Group.GID, out var shell)) + { + return PairOperationResult.Fail($"Group {dto.Group.GID} not found."); + } + + var updated = new GroupFullInfoDto( + dto.Group, + dto.Owner, + dto.GroupPermissions, + shell.GroupFullInfo.GroupUserPermissions, + shell.GroupFullInfo.GroupUserInfo, + new Dictionary(shell.GroupFullInfo.GroupPairUserInfos, StringComparer.Ordinal)); + + shell.Update(updated); + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateGroupPairPermissions(GroupPairUserPermissionDto dto) + { + lock (_gate) + { + if (!_groups.TryGetValue(dto.Group.GID, out var shell)) + { + return PairOperationResult.Fail($"Group {dto.Group.GID} not found."); + } + + var updated = shell.GroupFullInfo with { GroupUserPermissions = dto.GroupPairPermissions }; + shell.Update(updated); + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateGroupPermissions(GroupPermissionDto dto) + { + lock (_gate) + { + if (!_groups.TryGetValue(dto.Group.GID, out var shell)) + { + return PairOperationResult.Fail($"Group {dto.Group.GID} not found."); + } + + var updated = shell.GroupFullInfo with { GroupPermissions = dto.Permissions }; + shell.Update(updated); + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateGroupPairStatus(GroupPairUserInfoDto dto) + { + lock (_gate) + { + if (_pairs.TryGetValue(dto.UID, out var connection)) + { + connection.EnsureGroupRelationship(dto.GID, dto.GroupUserInfo == GroupPairUserInfo.None ? null : dto.GroupUserInfo); + } + + if (_groups.TryGetValue(dto.GID, out var shell)) + { + var infos = new Dictionary(shell.GroupFullInfo.GroupPairUserInfos, StringComparer.Ordinal) + { + [dto.UID] = dto.GroupUserInfo + }; + var updated = shell.GroupFullInfo with { GroupPairUserInfos = infos }; + shell.Update(updated); + } + + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateGroupStatus(GroupPairUserInfoDto dto) + { + lock (_gate) + { + if (!_groups.TryGetValue(dto.GID, out var shell)) + { + return PairOperationResult.Fail($"Group {dto.GID} not found."); + } + + var updated = shell.GroupFullInfo with { GroupUserInfo = dto.GroupUserInfo }; + shell.Update(updated); + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateOtherPermissions(UserPermissionsDto dto) + { + lock (_gate) + { + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {dto.User.UID} not found."); + } + + connection.UpdatePermissions(connection.SelfToOtherPermissions, dto.Permissions); + return PairOperationResult.Ok(); + } + } + + public PairOperationResult UpdateSelfPermissions(UserPermissionsDto dto) + { + lock (_gate) + { + if (!_pairs.TryGetValue(dto.User.UID, out var connection)) + { + return PairOperationResult.Fail($"Pair {dto.User.UID} not found."); + } + + connection.UpdatePermissions(dto.Permissions, connection.OtherToSelfPermissions); + return PairOperationResult.Ok(); + } + } + + private PairConnection GetOrCreatePair(UserData user) + { + return GetOrCreatePair(user, out _); + } + + private PairConnection GetOrCreatePair(UserData user, out bool created) + { + if (_pairs.TryGetValue(user.UID, out var connection)) + { + created = false; + return connection; + } + + connection = new PairConnection(user); + _pairs[user.UID] = connection; + created = true; + return connection; + } + + private Syncshell GetOrCreateShell(GroupData group) + { + if (_groups.TryGetValue(group.GID, out var shell)) + { + return shell; + } + + var placeholder = new GroupFullInfoDto( + group, + new UserData(string.Empty), + GroupPermissions.NoneSet, + GroupUserPreferredPermissions.NoneSet, + GroupPairUserInfo.None, + new Dictionary(StringComparer.Ordinal)); + + shell = new Syncshell(placeholder); + _groups[group.GID] = shell; + return shell; + } + + private PairRegistration? TryRemovePairIfNoConnection(PairConnection connection) + { + if (connection.HasAnyConnection) + { + return null; + } + + if (connection.IsOnline) + { + connection.SetOffline(); + } + + var userId = connection.User.UID; + _pairs.Remove(userId); + foreach (var shell in _groups.Values) + { + shell.Users.Remove(userId); + } + + return new PairRegistration(new PairUniqueIdentifier(userId), connection.Ident); + } + + public static PairConnection CreateFromFullData(UserFullPairDto dto) + { + var connection = new PairConnection(dto.User); + connection.UpdatePermissions(dto.OwnPermissions, dto.OtherPermissions); + connection.UpdateStatus(dto.IndividualPairStatus == IndividualPairStatus.None ? null : dto.IndividualPairStatus); + + foreach (var groupId in dto.Groups) + { + connection.EnsureGroupRelationship(groupId, null); + } + + return connection; + } + + public static PairConnection CreateFromPartialData(UserPairDto dto) + { + var connection = new PairConnection(dto.User); + connection.UpdatePermissions(dto.OwnPermissions, dto.OtherPermissions); + connection.UpdateStatus(dto.IndividualPairStatus == IndividualPairStatus.None ? null : dto.IndividualPairStatus); + return connection; + } + + public static GroupPairRelationship CreateGroupPairRelationshipFromFullInfo(string userUid, GroupFullInfoDto fullInfo) + { + return new GroupPairRelationship(fullInfo.Group.GID, + fullInfo.GroupPairUserInfos.TryGetValue(userUid, out var info) && info != GroupPairUserInfo.None + ? info + : null); + } +} diff --git a/LightlessSync/PlayerData/Pairs/PairState.cs b/LightlessSync/PlayerData/Pairs/PairState.cs new file mode 100644 index 0000000..0e2a508 --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/PairState.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using LightlessSync.API.Data; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Data.Extensions; +using LightlessSync.API.Dto.Group; + +namespace LightlessSync.PlayerData.Pairs; + +public readonly struct PairOperationResult +{ + private PairOperationResult(bool success, string? error) + { + Success = success; + Error = error; + } + + public bool Success { get; } + public string? Error { get; } + + public static PairOperationResult Ok() => new(true, null); + + public static PairOperationResult Fail(string error) => new(false, error); +} + +public readonly struct PairOperationResult +{ + private PairOperationResult(bool success, T value, string? error) + { + Success = success; + Value = value; + Error = error; + } + + public bool Success { get; } + public T Value { get; } + public string? Error { get; } + + public static PairOperationResult Ok(T value) => new(true, value, null); + + public static PairOperationResult Fail(string error) => new(false, default!, error); +} + +public sealed record PairRegistration(PairUniqueIdentifier PairIdent, string? CharacterIdent); + +public sealed class GroupPairRelationship +{ + public GroupPairRelationship(string groupId, GroupPairUserInfo? info) + { + GroupId = groupId; + UserInfo = info; + } + + public string GroupId { get; } + public GroupPairUserInfo? UserInfo { get; private set; } + + public void SetUserInfo(GroupPairUserInfo? info) + { + UserInfo = info; + } +} + +public sealed class PairConnection +{ + public PairConnection(UserData user) + { + User = user; + Groups = new Dictionary(StringComparer.Ordinal); + } + + public UserData User { get; } + public bool IsOnline { get; private set; } + public string? Ident { get; private set; } + public UserPermissions SelfToOtherPermissions { get; private set; } = UserPermissions.NoneSet; + public UserPermissions OtherToSelfPermissions { get; private set; } = UserPermissions.NoneSet; + public IndividualPairStatus? IndividualPairStatus { get; private set; } + public Dictionary Groups { get; } + + public bool IsPaused => SelfToOtherPermissions.IsPaused(); + public bool IsDirectlyPaired => IndividualPairStatus is not null && IndividualPairStatus != API.Data.Enum.IndividualPairStatus.None; + public bool IsOneSided => IndividualPairStatus == API.Data.Enum.IndividualPairStatus.OneSided; + public bool HasAnyConnection => IsDirectlyPaired || Groups.Count > 0; + + public void SetOnline(string? ident) + { + IsOnline = true; + Ident = ident; + } + + public void SetOffline() + { + IsOnline = false; + } + + public void UpdatePermissions(UserPermissions own, UserPermissions other) + { + SelfToOtherPermissions = own; + OtherToSelfPermissions = other; + } + + public void UpdateStatus(IndividualPairStatus? status) + { + IndividualPairStatus = status; + } + + public void EnsureGroupRelationship(string groupId, GroupPairUserInfo? info) + { + if (Groups.TryGetValue(groupId, out var relationship)) + { + relationship.SetUserInfo(info); + } + else + { + Groups[groupId] = new GroupPairRelationship(groupId, info); + } + } + + public void RemoveGroupRelationship(string groupId) + { + Groups.Remove(groupId); + } +} + +public sealed class Syncshell +{ + public Syncshell(GroupFullInfoDto dto) + { + GroupFullInfo = dto; + Users = new Dictionary(StringComparer.Ordinal); + } + + public GroupFullInfoDto GroupFullInfo { get; private set; } + public Dictionary Users { get; } + + public void Update(GroupFullInfoDto dto) + { + GroupFullInfo = dto; + } +} + +public sealed class PairState +{ + public CharacterData? CharacterData { get; set; } + public Guid? TemporaryCollectionId { get; set; } + + public bool IsEmpty => CharacterData is null && (TemporaryCollectionId is null || TemporaryCollectionId == Guid.Empty); +} + +public readonly record struct PairUniqueIdentifier(string UserId); diff --git a/LightlessSync/PlayerData/Pairs/PairStateCache.cs b/LightlessSync/PlayerData/Pairs/PairStateCache.cs new file mode 100644 index 0000000..67e8c8c --- /dev/null +++ b/LightlessSync/PlayerData/Pairs/PairStateCache.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using LightlessSync.API.Data; +using LightlessSync.Utils; + +namespace LightlessSync.PlayerData.Pairs; + +public sealed class PairStateCache +{ + private readonly ConcurrentDictionary _cache = new(StringComparer.Ordinal); + + public void Store(string ident, CharacterData data) + { + if (string.IsNullOrEmpty(ident) || data is null) + { + return; + } + + var state = _cache.GetOrAdd(ident, _ => new PairState()); + state.CharacterData = data.DeepClone(); + } + + public CharacterData? TryLoad(string ident) + { + if (string.IsNullOrEmpty(ident)) + { + return null; + } + + if (_cache.TryGetValue(ident, out var state) && state.CharacterData is not null) + { + return state.CharacterData.DeepClone(); + } + + return null; + } + + public Guid? TryGetTemporaryCollection(string ident) + { + if (string.IsNullOrEmpty(ident)) + { + return null; + } + + if (_cache.TryGetValue(ident, out var state)) + { + return state.TemporaryCollectionId; + } + + return null; + } + + public Guid? StoreTemporaryCollection(string ident, Guid collection) + { + if (string.IsNullOrEmpty(ident) || collection == Guid.Empty) + { + return null; + } + + var state = _cache.GetOrAdd(ident, _ => new PairState()); + state.TemporaryCollectionId = collection; + return collection; + } + + public Guid? ClearTemporaryCollection(string ident) + { + if (string.IsNullOrEmpty(ident)) + { + return null; + } + + if (_cache.TryGetValue(ident, out var state)) + { + var existing = state.TemporaryCollectionId; + state.TemporaryCollectionId = null; + TryRemoveIfEmpty(ident, state); + return existing; + } + + return null; + } + + public IReadOnlyList ClearAllTemporaryCollections() + { + var removed = new List(); + foreach (var (ident, state) in _cache) + { + if (state.TemporaryCollectionId is { } guid && guid != Guid.Empty) + { + removed.Add(guid); + state.TemporaryCollectionId = null; + } + + TryRemoveIfEmpty(ident, state); + } + + return removed; + } + + public void Clear(string ident) + { + if (string.IsNullOrEmpty(ident)) + { + return; + } + + _cache.TryRemove(ident, out _); + } + + private void TryRemoveIfEmpty(string ident, PairState state) + { + if (state.IsEmpty) + { + _cache.TryRemove(ident, out _); + } + } +} diff --git a/LightlessSync/PlayerData/Pairs/VisibleUserDataDistributor.cs b/LightlessSync/PlayerData/Pairs/VisibleUserDataDistributor.cs index 6ead2ca..da53332 100644 --- a/LightlessSync/PlayerData/Pairs/VisibleUserDataDistributor.cs +++ b/LightlessSync/PlayerData/Pairs/VisibleUserDataDistributor.cs @@ -1,10 +1,17 @@ +using System; using LightlessSync.API.Data; -using LightlessSync.Services; -using LightlessSync.Services.Mediator; +using LightlessSync.API.Data.Comparer; +using LightlessSync.PlayerData.Pairs; using LightlessSync.Utils; +using LightlessSync.Services.Mediator; +using LightlessSync.Services; using LightlessSync.WebAPI; using LightlessSync.WebAPI.Files; using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace LightlessSync.PlayerData.Pairs; @@ -13,22 +20,24 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase private readonly ApiController _apiController; private readonly DalamudUtilService _dalamudUtil; private readonly FileUploadManager _fileTransferManager; - private readonly PairManager _pairManager; + private readonly PairLedger _pairLedger; private CharacterData? _lastCreatedData; private CharacterData? _uploadingCharacterData = null; private readonly List _previouslyVisiblePlayers = []; private Task? _fileUploadTask = null; - private readonly HashSet _usersToPushDataTo = []; + private readonly HashSet _usersToPushDataTo = new(UserDataComparer.Instance); private readonly SemaphoreSlim _pushDataSemaphore = new(1, 1); private readonly CancellationTokenSource _runtimeCts = new(); + private readonly Dictionary _lastPushedHashes = new(StringComparer.Ordinal); + private readonly object _pushSync = new(); public VisibleUserDataDistributor(ILogger logger, ApiController apiController, DalamudUtilService dalamudUtil, - PairManager pairManager, LightlessMediator mediator, FileUploadManager fileTransferManager) : base(logger, mediator) + PairLedger pairLedger, LightlessMediator mediator, FileUploadManager fileTransferManager) : base(logger, mediator) { _apiController = apiController; _dalamudUtil = dalamudUtil; - _pairManager = pairManager; + _pairLedger = pairLedger; _fileTransferManager = fileTransferManager; Mediator.Subscribe(this, (_) => FrameworkOnUpdate()); Mediator.Subscribe(this, (msg) => @@ -47,7 +56,7 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase }); Mediator.Subscribe(this, (_) => PushToAllVisibleUsers()); - Mediator.Subscribe(this, (_) => _previouslyVisiblePlayers.Clear()); + Mediator.Subscribe(this, (_) => HandleDisconnected()); } protected override void Dispose(bool disposing) @@ -63,15 +72,18 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase private void PushToAllVisibleUsers(bool forced = false) { - foreach (var user in _pairManager.GetVisibleUsers()) + lock (_pushSync) { - _usersToPushDataTo.Add(user); - } + foreach (var user in GetVisibleUsers()) + { + _usersToPushDataTo.Add(user); + } - if (_usersToPushDataTo.Count > 0) - { - Logger.LogDebug("Pushing data {hash} for {count} visible players", _lastCreatedData?.DataHash.Value ?? "UNKNOWN", _usersToPushDataTo.Count); - PushCharacterData(forced); + if (_usersToPushDataTo.Count > 0) + { + Logger.LogDebug("Pushing data {hash} for {count} visible players", _lastCreatedData?.DataHash.Value ?? "UNKNOWN", _usersToPushDataTo.Count); + PushCharacterData_internalLocked(forced); + } } } @@ -79,8 +91,10 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase { if (!_dalamudUtil.GetIsPlayerPresent() || !_apiController.IsConnected) return; - var allVisibleUsers = _pairManager.GetVisibleUsers(); - var newVisibleUsers = allVisibleUsers.Except(_previouslyVisiblePlayers).ToList(); + var allVisibleUsers = GetVisibleUsers(); + var newVisibleUsers = allVisibleUsers + .Except(_previouslyVisiblePlayers, UserDataComparer.Instance) + .ToList(); _previouslyVisiblePlayers.Clear(); _previouslyVisiblePlayers.AddRange(allVisibleUsers); if (newVisibleUsers.Count == 0) return; @@ -88,56 +102,144 @@ public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase Logger.LogDebug("Scheduling character data push of {data} to {users}", _lastCreatedData?.DataHash.Value ?? string.Empty, string.Join(", ", newVisibleUsers.Select(k => k.AliasOrUID))); - foreach (var user in newVisibleUsers) + lock (_pushSync) { - _usersToPushDataTo.Add(user); + foreach (var user in newVisibleUsers) + { + _usersToPushDataTo.Add(user); + } + PushCharacterData_internalLocked(); } - PushCharacterData(); } private void PushCharacterData(bool forced = false) + { + lock (_pushSync) + { + PushCharacterData_internalLocked(forced); + } + } + + private void PushCharacterData_internalLocked(bool forced = false) { if (_lastCreatedData == null || _usersToPushDataTo.Count == 0) return; + if (!_apiController.IsConnected || !_fileTransferManager.IsReady) + { + Logger.LogTrace("Skipping character push. Connected: {connected}, UploadManagerReady: {ready}", + _apiController.IsConnected, _fileTransferManager.IsReady); + return; + } _ = Task.Run(async () => { try { - forced |= _uploadingCharacterData?.DataHash != _lastCreatedData.DataHash; + Task? uploadTask; + bool forcedPush; + lock (_pushSync) + { + if (_lastCreatedData == null || _usersToPushDataTo.Count == 0) return; + forcedPush = forced | (_uploadingCharacterData?.DataHash != _lastCreatedData.DataHash); - if (_fileUploadTask == null || (_fileUploadTask?.IsCompleted ?? false) || forced) - { - _uploadingCharacterData = _lastCreatedData.DeepClone(); - Logger.LogDebug("Starting UploadTask for {hash}, Reason: TaskIsNull: {task}, TaskIsCompleted: {taskCpl}, Forced: {frc}", - _lastCreatedData.DataHash, _fileUploadTask == null, _fileUploadTask?.IsCompleted ?? false, forced); - _fileUploadTask = _fileTransferManager.UploadFiles(_uploadingCharacterData, [.. _usersToPushDataTo]); - } + if (_fileUploadTask == null || (_fileUploadTask?.IsCompleted ?? false) || forcedPush) + { + _uploadingCharacterData = _lastCreatedData.DeepClone(); + Logger.LogDebug("Starting UploadTask for {hash}, Reason: TaskIsNull: {task}, TaskIsCompleted: {taskCpl}, Forced: {frc}", + _lastCreatedData.DataHash, _fileUploadTask == null, _fileUploadTask?.IsCompleted ?? false, forcedPush); + _fileUploadTask = _fileTransferManager.UploadFiles(_uploadingCharacterData, [.. _usersToPushDataTo]); + } - if (_fileUploadTask != null) - { - var dataToSend = await _fileUploadTask.ConfigureAwait(false); + uploadTask = _fileUploadTask; + } + + var dataToSend = await uploadTask.ConfigureAwait(false); + var dataHash = dataToSend.DataHash.Value; await _pushDataSemaphore.WaitAsync(_runtimeCts.Token).ConfigureAwait(false); try { - if (_usersToPushDataTo.Count == 0) return; - Logger.LogDebug("Pushing {data} to {users}", dataToSend.DataHash, string.Join(", ", _usersToPushDataTo.Select(k => k.AliasOrUID))); - await _apiController.PushCharacterData(dataToSend, [.. _usersToPushDataTo]).ConfigureAwait(false); - _usersToPushDataTo.Clear(); + List recipients; + bool shouldSkip = false; + lock (_pushSync) + { + if (_usersToPushDataTo.Count == 0) return; + recipients = forcedPush + ? _usersToPushDataTo.ToList() + : _usersToPushDataTo + .Where(user => !_lastPushedHashes.TryGetValue(user.UID, out var sentHash) || !string.Equals(sentHash, dataHash, StringComparison.Ordinal)) + .ToList(); + + if (recipients.Count == 0 && !forcedPush) + { + Logger.LogTrace("All recipients already have character data hash {hash}, skipping push.", dataHash); + _usersToPushDataTo.Clear(); + shouldSkip = true; + } + } + + if (shouldSkip) + return; + + Logger.LogDebug("Pushing {data} to {users}", dataHash, string.Join(", ", recipients.Select(k => k.AliasOrUID))); + await _apiController.PushCharacterData(dataToSend, recipients).ConfigureAwait(false); + + lock (_pushSync) + { + foreach (var user in recipients) + { + _lastPushedHashes[user.UID] = dataHash; + _usersToPushDataTo.Remove(user); + } + + if (!forcedPush && _usersToPushDataTo.Count > 0) + { + foreach (var satisfied in _usersToPushDataTo + .Where(user => _lastPushedHashes.TryGetValue(user.UID, out var sentHash) && string.Equals(sentHash, dataHash, StringComparison.Ordinal)) + .ToList()) + { + _usersToPushDataTo.Remove(satisfied); + } + } + + if (forcedPush) + { + _usersToPushDataTo.Clear(); + } + } } finally { _pushDataSemaphore.Release(); } } - } - catch (OperationCanceledException) when (_runtimeCts.IsCancellationRequested) - { - Logger.LogDebug("PushCharacterData cancelled"); - } - catch (Exception ex) - { - Logger.LogError(ex, "Failed to push character data"); - } + catch (OperationCanceledException) when (_runtimeCts.IsCancellationRequested) + { + Logger.LogDebug("PushCharacterData cancelled"); + } + catch (Exception ex) + { + Logger.LogError(ex, "Failed to push character data"); + } }); } -} \ No newline at end of file + + private void HandleDisconnected() + { + _fileTransferManager.CancelUpload(); + _previouslyVisiblePlayers.Clear(); + + lock (_pushSync) + { + _usersToPushDataTo.Clear(); + _lastPushedHashes.Clear(); + _uploadingCharacterData = null; + _fileUploadTask = null; + } + } + + private List GetVisibleUsers() + { + return _pairLedger.GetVisiblePairs() + .Select(connection => connection.User) + .ToList(); + } +} diff --git a/LightlessSync/PlayerData/Services/CacheCreationService.cs b/LightlessSync/PlayerData/Services/CacheCreationService.cs index 9c64d8f..69a975e 100644 --- a/LightlessSync/PlayerData/Services/CacheCreationService.cs +++ b/LightlessSync/PlayerData/Services/CacheCreationService.cs @@ -20,6 +20,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase private readonly CancellationTokenSource _runtimeCts = new(); private CancellationTokenSource _creationCts = new(); private CancellationTokenSource _debounceCts = new(); + private string? _lastPublishedHash; private bool _haltCharaDataCreation; private bool _isZoning = false; @@ -183,7 +184,18 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase { if (_isZoning || _haltCharaDataCreation) return; - if (_cachesToCreate.Count == 0) return; + bool hasCaches; + _cacheCreateLock.Wait(); + try + { + hasCaches = _cachesToCreate.Count > 0; + } + finally + { + _cacheCreateLock.Release(); + } + + if (!hasCaches) return; if (_playerRelatedObjects.Any(p => p.Value.CurrentDrawCondition is not (GameObjectHandler.DrawCondition.None or GameObjectHandler.DrawCondition.DrawObjectZero or GameObjectHandler.DrawCondition.ObjectZero))) @@ -197,6 +209,11 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase _creationCts = new(); _cacheCreateLock.Wait(_creationCts.Token); var objectKindsToCreate = _cachesToCreate.ToList(); + if (objectKindsToCreate.Count == 0) + { + _cacheCreateLock.Release(); + return; + } foreach (var creationObj in objectKindsToCreate) { _currentlyCreating.Add(creationObj); @@ -225,8 +242,17 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase _playerData.SetFragment(kvp.Key, kvp.Value); } - Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI())); - _currentlyCreating.Clear(); + var apiData = _playerData.ToAPI(); + var currentHash = apiData.DataHash.Value; + if (string.Equals(_lastPublishedHash, currentHash, StringComparison.Ordinal)) + { + Logger.LogTrace("Cache creation produced identical character data ({hash}), skipping publish.", currentHash); + } + else + { + _lastPublishedHash = currentHash; + Mediator.Publish(new CharacterDataCreatedMessage(apiData)); + } } catch (OperationCanceledException) { @@ -238,6 +264,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase } finally { + _currentlyCreating.Clear(); Logger.LogDebug("Cache Creation complete"); } }); diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index 01a4de4..542d9a1 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -13,14 +13,19 @@ using LightlessSync.PlayerData.Factories; using LightlessSync.PlayerData.Pairs; using LightlessSync.PlayerData.Services; using LightlessSync.Services; +using LightlessSync.Services.Chat; +using LightlessSync.Services.ActorTracking; using LightlessSync.Services.CharaData; using LightlessSync.Services.Events; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; +using LightlessSync.Services.TextureCompression; using LightlessSync.UI; using LightlessSync.UI.Components; using LightlessSync.UI.Components.Popup; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Tags; +using LightlessSync.UI.Services; using LightlessSync.WebAPI; using LightlessSync.WebAPI.Files; using LightlessSync.WebAPI.SignalR; @@ -28,8 +33,11 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NReco.Logging.File; +using System; +using System.IO; using System.Net.Http.Headers; using System.Reflection; +using OtterTex; namespace LightlessSync; @@ -43,6 +51,7 @@ public sealed class Plugin : IDalamudPlugin ITextureProvider textureProvider, IContextMenu contextMenu, IGameInteropProvider gameInteropProvider, IGameConfig gameConfig, ISigScanner sigScanner, INamePlateGui namePlateGui, IAddonLifecycle addonLifecycle) { + NativeDll.Initialize(pluginInterface.AssemblyLocation.DirectoryName); if (!Directory.Exists(pluginInterface.ConfigDirectory.FullName)) Directory.CreateDirectory(pluginInterface.ConfigDirectory.FullName); var traceDir = Path.Join(pluginInterface.ConfigDirectory.FullName, "tracelog"); @@ -96,6 +105,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); @@ -103,11 +113,22 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(); + collection.AddSingleton(s => + { + var logger = s.GetRequiredService>(); + return new TextureMetadataHelper(logger, gameData); + }); + collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); - collection.AddSingleton(); collection.AddSingleton(); - collection.AddSingleton(); + collection.AddSingleton(s => new PairFactory( + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + new Lazy(() => s.GetRequiredService()), + s.GetRequiredService>())); collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); @@ -116,9 +137,15 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(s => new Lazy(() => s.GetRequiredService())); collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); - collection.AddSingleton(); + collection.AddSingleton(s => new TransientResourceManager(s.GetRequiredService>(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService())); collection.AddSingleton(); collection.AddSingleton(); @@ -141,30 +168,53 @@ public sealed class Plugin : IDalamudPlugin s.GetRequiredService>(), s.GetRequiredService())); collection.AddSingleton((s) => new DalamudUtilService(s.GetRequiredService>(), clientState, objectTable, framework, gameGui, condition, gameData, targetManager, gameConfig, - s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), - s.GetRequiredService(), s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), + s.GetRequiredService(), s.GetRequiredService(), new Lazy(() => s.GetRequiredService()))); + collection.AddSingleton(); + collection.AddSingleton(); + collection.AddSingleton(); + collection.AddSingleton(s => new PairHandlerRegistry( + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService>())); + collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton((s) => new DtrEntry( s.GetRequiredService>(), dtrBar, s.GetRequiredService(), s.GetRequiredService(), - s.GetRequiredService(), + s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); - collection.AddSingleton(s => new PairManager(s.GetRequiredService>(), s.GetRequiredService(), - s.GetRequiredService(), s.GetRequiredService(), contextMenu, s.GetRequiredService())); + collection.AddSingleton(s => new PairCoordinator( + s.GetRequiredService>(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService())); collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(addonLifecycle); - collection.AddSingleton(p => new ContextMenuService(contextMenu, pluginInterface, gameData, - p.GetRequiredService>(), p.GetRequiredService(), p.GetRequiredService(), objectTable, - p.GetRequiredService(), p.GetRequiredService(), p.GetRequiredService(), clientState)); + collection.AddSingleton(p => new ContextMenuService(contextMenu, pluginInterface, gameData, p.GetRequiredService>(), p.GetRequiredService(), p.GetRequiredService(), objectTable, + p.GetRequiredService(), + p.GetRequiredService(), + p.GetRequiredService(), + clientState, + p.GetRequiredService(), + p.GetRequiredService(), + p.GetRequiredService(), + p.GetRequiredService())); collection.AddSingleton((s) => new IpcCallerPenumbra(s.GetRequiredService>(), pluginInterface, - s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), + s.GetRequiredService())); collection.AddSingleton((s) => new IpcCallerGlamourer(s.GetRequiredService>(), pluginInterface, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddSingleton((s) => new IpcCallerCustomize(s.GetRequiredService>(), pluginInterface, @@ -190,7 +240,9 @@ public sealed class Plugin : IDalamudPlugin notificationManager, chatGui, s.GetRequiredService(), - s.GetRequiredService())); + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService())); collection.AddSingleton((s) => { var httpClient = new HttpClient(); @@ -199,6 +251,7 @@ public sealed class Plugin : IDalamudPlugin return httpClient; }); collection.AddSingleton((s) => new UiThemeConfigService(pluginInterface.ConfigDirectory.FullName)); + collection.AddSingleton((s) => new ChatConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => { var cfg = new LightlessConfigService(pluginInterface.ConfigDirectory.FullName); @@ -216,6 +269,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton((s) => new CharaDataConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); + collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton>(s => s.GetRequiredService()); @@ -226,8 +280,15 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton>(s => s.GetRequiredService()); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(sp => new ActorObjectService( + sp.GetRequiredService>(), + framework, + gameInteropProvider, + objectTable, + clientState, + sp.GetRequiredService())); collection.AddSingleton(); - collection.AddSingleton(s => new BroadcastScannerService( s.GetRequiredService>(), clientState, objectTable, framework, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + collection.AddSingleton(s => new BroadcastScannerService( s.GetRequiredService>(), framework, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); // add scoped services @@ -247,13 +308,14 @@ public sealed class Plugin : IDalamudPlugin collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); + collection.AddScoped(); collection.AddScoped((s) => new EditProfileUi(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), - s.GetRequiredService(), s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped(); collection.AddScoped((s) => new BroadcastUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); - collection.AddScoped((s) => new SyncshellFinderUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + collection.AddScoped((s) => new SyncshellFinderUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped(); collection.AddScoped((s) => new LightlessNotificationUi( @@ -268,8 +330,9 @@ public sealed class Plugin : IDalamudPlugin collection.AddScoped((s) => new UiService(s.GetRequiredService>(), pluginInterface.UiBuilder, s.GetRequiredService(), s.GetRequiredService(), s.GetServices(), s.GetRequiredService(), - s.GetRequiredService(), - s.GetRequiredService())); + s.GetRequiredService(), + s.GetRequiredService(), + s.GetRequiredService())); collection.AddScoped((s) => new CommandManagerService(commandManager, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); @@ -278,12 +341,14 @@ public sealed class Plugin : IDalamudPlugin pluginInterface, textureProvider, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped((s) => new NameplateService(s.GetRequiredService>(), s.GetRequiredService(), namePlateGui, clientState, - s.GetRequiredService(), s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped((s) => new NameplateHandler(s.GetRequiredService>(), addonLifecycle, gameGui, s.GetRequiredService(), - s.GetRequiredService(), s.GetRequiredService(), clientState, s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService(), clientState, s.GetRequiredService())); collection.AddHostedService(p => p.GetRequiredService()); + collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); + collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); diff --git a/LightlessSync/Services/ActorTracking/ActorObjectService.cs b/LightlessSync/Services/ActorTracking/ActorObjectService.cs new file mode 100644 index 0000000..2305c2a --- /dev/null +++ b/LightlessSync/Services/ActorTracking/ActorObjectService.cs @@ -0,0 +1,754 @@ +using LightlessSync; +using LightlessObjectKind = LightlessSync.API.Data.Enum.ObjectKind; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using Dalamud.Game; +using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.ClientState.Objects.Types; +using Dalamud.Hooking; +using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.Game.Character; +using FFXIVClientStructs.FFXIV.Client.Game.Object; +using LightlessSync.Services.Mediator; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; +using FFXIVClientStructs.Interop; +using System.Threading; + +namespace LightlessSync.Services.ActorTracking; + +public sealed unsafe class ActorObjectService : IHostedService, IDisposable +{ + public readonly record struct ActorDescriptor( + string Name, + string HashedContentId, + nint Address, + ushort ObjectIndex, + bool IsLocalPlayer, + bool IsInGpose, + DalamudObjectKind ObjectKind, + LightlessObjectKind? OwnedKind, + uint OwnerEntityId); + + private readonly ILogger _logger; + private readonly IFramework _framework; + private readonly IGameInteropProvider _interop; + private readonly IObjectTable _objectTable; + private readonly IClientState _clientState; + private readonly LightlessMediator _mediator; + + private readonly ConcurrentDictionary _activePlayers = new(); + private readonly ConcurrentDictionary _actorsByHash = new(StringComparer.Ordinal); + private readonly ConcurrentDictionary> _actorsByName = new(StringComparer.Ordinal); + private ActorDescriptor[] _playerCharacterSnapshot = Array.Empty(); + private nint[] _playerAddressSnapshot = Array.Empty(); + private readonly HashSet _renderedPlayers = new(); + private readonly HashSet _renderedCompanions = new(); + private readonly Dictionary _ownedObjects = new(); + private nint[] _renderedPlayerSnapshot = Array.Empty(); + private nint[] _renderedCompanionSnapshot = Array.Empty(); + private nint[] _ownedObjectSnapshot = Array.Empty(); + private IReadOnlyDictionary _ownedObjectMapSnapshot = new Dictionary(); + private nint _localPlayerAddress = nint.Zero; + private nint _localPetAddress = nint.Zero; + private nint _localMinionMountAddress = nint.Zero; + private nint _localCompanionAddress = nint.Zero; + + private Hook? _onInitializeHook; + private Hook? _onTerminateHook; + private Hook? _onDestructorHook; + private Hook? _onCompanionInitializeHook; + private Hook? _onCompanionTerminateHook; + + private bool _hooksActive; + private static readonly TimeSpan SnapshotRefreshInterval = TimeSpan.FromSeconds(1); + private DateTime _nextRefreshAllowed = DateTime.MinValue; + + public ActorObjectService( + ILogger logger, + IFramework framework, + IGameInteropProvider interop, + IObjectTable objectTable, + IClientState clientState, + LightlessMediator mediator) + { + _logger = logger; + _framework = framework; + _interop = interop; + _objectTable = objectTable; + _clientState = clientState; + _mediator = mediator; + } + + public IReadOnlyList PlayerAddresses => Volatile.Read(ref _playerAddressSnapshot); + + public IEnumerable PlayerDescriptors => _activePlayers.Values; + public IReadOnlyList PlayerCharacterDescriptors => Volatile.Read(ref _playerCharacterSnapshot); + + public bool TryGetActorByHash(string hash, out ActorDescriptor descriptor) => _actorsByHash.TryGetValue(hash, out descriptor); + public bool TryGetPlayerByName(string name, out ActorDescriptor descriptor) + { + descriptor = default; + + if (!_actorsByName.TryGetValue(name, out var entries) || entries.IsEmpty) + return false; + + ActorDescriptor? best = null; + foreach (var candidate in entries.Values) + { + if (best is null || IsBetterNameMatch(candidate, best.Value)) + { + best = candidate; + } + } + + if (best is { } selected) + { + descriptor = selected; + return true; + } + + return false; + } + public bool HooksActive => _hooksActive; + public IReadOnlyList RenderedPlayerAddresses => Volatile.Read(ref _renderedPlayerSnapshot); + public IReadOnlyList RenderedCompanionAddresses => Volatile.Read(ref _renderedCompanionSnapshot); + public IReadOnlyList OwnedObjectAddresses => Volatile.Read(ref _ownedObjectSnapshot); + public IReadOnlyDictionary OwnedObjects => Volatile.Read(ref _ownedObjectMapSnapshot); + public nint LocalPlayerAddress => Volatile.Read(ref _localPlayerAddress); + public nint LocalPetAddress => Volatile.Read(ref _localPetAddress); + public nint LocalMinionOrMountAddress => Volatile.Read(ref _localMinionMountAddress); + public nint LocalCompanionAddress => Volatile.Read(ref _localCompanionAddress); + + public bool TryGetOwnedObject(LightlessObjectKind kind, out nint address) + { + address = kind switch + { + LightlessObjectKind.Player => Volatile.Read(ref _localPlayerAddress), + LightlessObjectKind.Pet => Volatile.Read(ref _localPetAddress), + LightlessObjectKind.MinionOrMount => Volatile.Read(ref _localMinionMountAddress), + LightlessObjectKind.Companion => Volatile.Read(ref _localCompanionAddress), + _ => nint.Zero + }; + + return address != nint.Zero; + } + + public bool TryGetOwnedActor(uint ownerEntityId, LightlessObjectKind? kindFilter, out ActorDescriptor descriptor) + { + descriptor = default; + foreach (var candidate in _activePlayers.Values) + { + if (candidate.OwnerEntityId != ownerEntityId) + continue; + + if (kindFilter.HasValue && candidate.OwnedKind != kindFilter) + continue; + + descriptor = candidate; + return true; + } + + return false; + } + + public bool TryGetPlayerAddressByHash(string hash, out nint address) + { + if (TryGetActorByHash(hash, out var descriptor) && descriptor.Address != nint.Zero) + { + address = descriptor.Address; + return true; + } + + address = nint.Zero; + return false; + } + + public void RefreshTrackedActors(bool force = false) + { + var now = DateTime.UtcNow; + if (!force && _hooksActive) + { + if (now < _nextRefreshAllowed) + return; + + _nextRefreshAllowed = now + SnapshotRefreshInterval; + } + + if (_framework.IsInFrameworkUpdateThread) + { + RefreshTrackedActorsInternal(); + } + else + { + _framework.RunOnFrameworkThread(RefreshTrackedActorsInternal); + } + } + + public Task StartAsync(CancellationToken cancellationToken) + { + try + { + InitializeHooks(); + var warmupTask = WarmupExistingActors(); + return warmupTask; + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to initialize ActorObjectService hooks, falling back to empty cache."); + DisposeHooks(); + return Task.CompletedTask; + } + } + + public Task StopAsync(CancellationToken cancellationToken) + { + DisposeHooks(); + _activePlayers.Clear(); + _actorsByHash.Clear(); + _actorsByName.Clear(); + Volatile.Write(ref _playerCharacterSnapshot, Array.Empty()); + Volatile.Write(ref _playerAddressSnapshot, Array.Empty()); + Volatile.Write(ref _renderedPlayerSnapshot, Array.Empty()); + Volatile.Write(ref _renderedCompanionSnapshot, Array.Empty()); + Volatile.Write(ref _ownedObjectSnapshot, Array.Empty()); + Volatile.Write(ref _ownedObjectMapSnapshot, new Dictionary()); + Volatile.Write(ref _localPlayerAddress, nint.Zero); + Volatile.Write(ref _localPetAddress, nint.Zero); + Volatile.Write(ref _localMinionMountAddress, nint.Zero); + Volatile.Write(ref _localCompanionAddress, nint.Zero); + _renderedPlayers.Clear(); + _renderedCompanions.Clear(); + _ownedObjects.Clear(); + return Task.CompletedTask; + } + + private void InitializeHooks() + { + if (_hooksActive) + return; + + _onInitializeHook = _interop.HookFromAddress( + (nint)Character.StaticVirtualTablePointer->OnInitialize, + OnCharacterInitialized); + + _onTerminateHook = _interop.HookFromAddress( + (nint)Character.StaticVirtualTablePointer->Terminate, + OnCharacterTerminated); + + _onDestructorHook = _interop.HookFromAddress( + (nint)Character.StaticVirtualTablePointer->Dtor, + OnCharacterDisposed); + + _onCompanionInitializeHook = _interop.HookFromAddress( + (nint)Companion.StaticVirtualTablePointer->OnInitialize, + OnCompanionInitialized); + + _onCompanionTerminateHook = _interop.HookFromAddress( + (nint)Companion.StaticVirtualTablePointer->Terminate, + OnCompanionTerminated); + + _onInitializeHook.Enable(); + _onTerminateHook.Enable(); + _onDestructorHook.Enable(); + _onCompanionInitializeHook.Enable(); + _onCompanionTerminateHook.Enable(); + + _hooksActive = true; + _logger.LogDebug("ActorObjectService hooks enabled."); + } + + private Task WarmupExistingActors() + { + return _framework.RunOnFrameworkThread(() => + { + RefreshTrackedActorsInternal(); + _nextRefreshAllowed = DateTime.UtcNow + SnapshotRefreshInterval; + }); + } + + private void OnCharacterInitialized(Character* chara) + { + try + { + _onInitializeHook!.Original(chara); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error invoking original character initialize."); + } + + QueueFrameworkUpdate(() => TrackGameObject((GameObject*)chara)); + } + + private void OnCharacterTerminated(Character* chara) + { + var address = (nint)chara; + QueueFrameworkUpdate(() => UntrackGameObject(address)); + try + { + _onTerminateHook!.Original(chara); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error invoking original character terminate."); + } + } + + private GameObject* OnCharacterDisposed(Character* chara, byte freeMemory) + { + var address = (nint)chara; + QueueFrameworkUpdate(() => UntrackGameObject(address)); + try + { + return _onDestructorHook!.Original(chara, freeMemory); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error invoking original character destructor."); + return null; + } + } + + private void TrackGameObject(GameObject* gameObject) + { + if (gameObject == null) + return; + + var objectKind = (DalamudObjectKind)gameObject->ObjectKind; + + if (!IsSupportedObjectKind(objectKind)) + return; + + if (BuildDescriptor(gameObject, objectKind) is not { } descriptor) + return; + + if (descriptor.ObjectKind != DalamudObjectKind.Player && descriptor.OwnedKind is null) + return; + + if (_activePlayers.TryGetValue(descriptor.Address, out var existing)) + { + RemoveDescriptorFromIndexes(existing); + RemoveDescriptorFromCollections(existing); + } + + _activePlayers[descriptor.Address] = descriptor; + IndexDescriptor(descriptor); + AddDescriptorToCollections(descriptor); + RebuildSnapshots(); + + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Actor tracked: {Name} addr={Address:X} idx={Index} owned={OwnedKind} local={Local} gpose={Gpose}", + descriptor.Name, + descriptor.Address, + descriptor.ObjectIndex, + descriptor.OwnedKind?.ToString() ?? "", + descriptor.IsLocalPlayer, + descriptor.IsInGpose); + } + + _mediator.Publish(new ActorTrackedMessage(descriptor)); + } + + private ActorDescriptor? BuildDescriptor(GameObject* gameObject, DalamudObjectKind objectKind) + { + if (gameObject == null) + return null; + + var address = (nint)gameObject; + string name = string.Empty; + ushort objectIndex = (ushort)gameObject->ObjectIndex; + bool isInGpose = objectIndex >= 200; + bool isLocal = _clientState.LocalPlayer?.Address == address; + string hashedCid = string.Empty; + + if (_objectTable.CreateObjectReference(address) is IPlayerCharacter playerCharacter) + { + name = playerCharacter.Name.TextValue ?? string.Empty; + objectIndex = playerCharacter.ObjectIndex; + isInGpose = objectIndex >= 200; + isLocal = playerCharacter.Address == _clientState.LocalPlayer?.Address; + } + else + { + name = gameObject->NameString ?? string.Empty; + } + + if (objectKind == DalamudObjectKind.Player) + { + hashedCid = DalamudUtilService.GetHashedCIDFromPlayerPointer(address); + } + + var (ownedKind, ownerEntityId) = DetermineOwnedKind(gameObject, objectKind, isLocal); + + return new ActorDescriptor(name, hashedCid, address, objectIndex, isLocal, isInGpose, objectKind, ownedKind, ownerEntityId); + } + + private (LightlessObjectKind? OwnedKind, uint OwnerEntityId) DetermineOwnedKind(GameObject* gameObject, DalamudObjectKind objectKind, bool isLocalPlayer) + { + if (gameObject == null) + return (null, 0); + + if (objectKind == DalamudObjectKind.Player) + { + var entityId = ((Character*)gameObject)->EntityId; + return (isLocalPlayer ? LightlessObjectKind.Player : null, entityId); + } + + if (isLocalPlayer) + { + var entityId = ((Character*)gameObject)->EntityId; + return (LightlessObjectKind.Player, entityId); + } + + if (_clientState.LocalPlayer is not { } localPlayer) + return (null, 0); + + var ownerId = gameObject->OwnerId; + if (ownerId == 0) + { + var character = (Character*)gameObject; + if (character != null) + { + ownerId = character->CompanionOwnerId; + if (ownerId == 0) + { + var parent = character->GetParentCharacter(); + if (parent != null) + { + ownerId = parent->EntityId; + } + } + } + } + + if (ownerId == 0 || ownerId != localPlayer.EntityId) + return (null, ownerId); + + var ownedKind = objectKind switch + { + DalamudObjectKind.MountType => LightlessObjectKind.MinionOrMount, + DalamudObjectKind.Companion => LightlessObjectKind.MinionOrMount, + DalamudObjectKind.BattleNpc => gameObject->BattleNpcSubKind switch + { + BattleNpcSubKind.Buddy => LightlessObjectKind.Companion, + BattleNpcSubKind.Pet => LightlessObjectKind.Pet, + _ => (LightlessObjectKind?)null, + }, + _ => (LightlessObjectKind?)null, + }; + + return (ownedKind, ownerId); + } + + private void UntrackGameObject(nint address) + { + if (address == nint.Zero) + return; + + if (_activePlayers.TryRemove(address, out var descriptor)) + { + RemoveDescriptorFromIndexes(descriptor); + RemoveDescriptorFromCollections(descriptor); + RebuildSnapshots(); + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Actor untracked: {Name} addr={Address:X} idx={Index} owned={OwnedKind}", + descriptor.Name, + descriptor.Address, + descriptor.ObjectIndex, + descriptor.OwnedKind?.ToString() ?? ""); + } + + _mediator.Publish(new ActorUntrackedMessage(descriptor)); + } + } + + private void RefreshTrackedActorsInternal() + { + var addresses = EnumerateActiveCharacterAddresses(); + HashSet seen = new(addresses.Count); + + foreach (var address in addresses) + { + if (address == nint.Zero) + continue; + + if (!seen.Add(address)) + continue; + + if (_activePlayers.ContainsKey(address)) + continue; + + TrackGameObject((GameObject*)address); + } + + var stale = _activePlayers.Keys.Where(addr => !seen.Contains(addr)).ToList(); + foreach (var staleAddress in stale) + { + UntrackGameObject(staleAddress); + } + + if (_hooksActive) + { + _nextRefreshAllowed = DateTime.UtcNow + SnapshotRefreshInterval; + } + } + + private void IndexDescriptor(ActorDescriptor descriptor) + { + if (!string.IsNullOrEmpty(descriptor.HashedContentId)) + { + _actorsByHash[descriptor.HashedContentId] = descriptor; + } + + if (descriptor.ObjectKind == DalamudObjectKind.Player && !string.IsNullOrEmpty(descriptor.Name)) + { + var bucket = _actorsByName.GetOrAdd(descriptor.Name, _ => new ConcurrentDictionary()); + bucket[descriptor.Address] = descriptor; + } + } + + private static bool IsBetterNameMatch(ActorDescriptor candidate, ActorDescriptor current) + { + if (!candidate.IsInGpose && current.IsInGpose) + return true; + if (candidate.IsInGpose && !current.IsInGpose) + return false; + + return candidate.ObjectIndex < current.ObjectIndex; + } + + private void OnCompanionInitialized(Companion* companion) + { + try + { + _onCompanionInitializeHook!.Original(companion); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error invoking original companion initialize."); + } + + QueueFrameworkUpdate(() => TrackGameObject((GameObject*)companion)); + } + + private void OnCompanionTerminated(Companion* companion) + { + var address = (nint)companion; + QueueFrameworkUpdate(() => UntrackGameObject(address)); + try + { + _onCompanionTerminateHook!.Original(companion); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error invoking original companion terminate."); + } + } + + private void RemoveDescriptorFromIndexes(ActorDescriptor descriptor) + { + if (!string.IsNullOrEmpty(descriptor.HashedContentId)) + { + _actorsByHash.TryRemove(descriptor.HashedContentId, out _); + } + + if (descriptor.ObjectKind == DalamudObjectKind.Player && !string.IsNullOrEmpty(descriptor.Name)) + { + if (_actorsByName.TryGetValue(descriptor.Name, out var bucket)) + { + bucket.TryRemove(descriptor.Address, out _); + if (bucket.IsEmpty) + { + _actorsByName.TryRemove(descriptor.Name, out _); + } + } + } + } + + private void AddDescriptorToCollections(ActorDescriptor descriptor) + { + if (descriptor.ObjectKind == DalamudObjectKind.Player) + { + _renderedPlayers.Add(descriptor.Address); + if (descriptor.IsLocalPlayer) + { + Volatile.Write(ref _localPlayerAddress, descriptor.Address); + } + } + else if (descriptor.ObjectKind == DalamudObjectKind.Companion) + { + _renderedCompanions.Add(descriptor.Address); + } + + if (descriptor.OwnedKind is { } ownedKind) + { + _ownedObjects[descriptor.Address] = ownedKind; + switch (ownedKind) + { + case LightlessObjectKind.Player: + Volatile.Write(ref _localPlayerAddress, descriptor.Address); + break; + case LightlessObjectKind.Pet: + Volatile.Write(ref _localPetAddress, descriptor.Address); + break; + case LightlessObjectKind.MinionOrMount: + Volatile.Write(ref _localMinionMountAddress, descriptor.Address); + break; + case LightlessObjectKind.Companion: + Volatile.Write(ref _localCompanionAddress, descriptor.Address); + break; + } + } + } + + private void RemoveDescriptorFromCollections(ActorDescriptor descriptor) + { + if (descriptor.ObjectKind == DalamudObjectKind.Player) + { + _renderedPlayers.Remove(descriptor.Address); + if (descriptor.IsLocalPlayer && Volatile.Read(ref _localPlayerAddress) == descriptor.Address) + { + Volatile.Write(ref _localPlayerAddress, nint.Zero); + } + } + else if (descriptor.ObjectKind == DalamudObjectKind.Companion) + { + _renderedCompanions.Remove(descriptor.Address); + if (Volatile.Read(ref _localCompanionAddress) == descriptor.Address) + { + Volatile.Write(ref _localCompanionAddress, nint.Zero); + } + } + + if (descriptor.OwnedKind is { } ownedKind) + { + _ownedObjects.Remove(descriptor.Address); + switch (ownedKind) + { + case LightlessObjectKind.Player when Volatile.Read(ref _localPlayerAddress) == descriptor.Address: + Volatile.Write(ref _localPlayerAddress, nint.Zero); + break; + case LightlessObjectKind.Pet when Volatile.Read(ref _localPetAddress) == descriptor.Address: + Volatile.Write(ref _localPetAddress, nint.Zero); + break; + case LightlessObjectKind.MinionOrMount when Volatile.Read(ref _localMinionMountAddress) == descriptor.Address: + Volatile.Write(ref _localMinionMountAddress, nint.Zero); + break; + case LightlessObjectKind.Companion when Volatile.Read(ref _localCompanionAddress) == descriptor.Address: + Volatile.Write(ref _localCompanionAddress, nint.Zero); + break; + } + } + } + + private void RebuildSnapshots() + { + var playerDescriptors = _activePlayers.Values + .Where(descriptor => descriptor.ObjectKind == DalamudObjectKind.Player) + .ToArray(); + + Volatile.Write(ref _playerCharacterSnapshot, playerDescriptors); + Volatile.Write(ref _playerAddressSnapshot, playerDescriptors.Select(d => d.Address).ToArray()); + Volatile.Write(ref _renderedPlayerSnapshot, _renderedPlayers.ToArray()); + Volatile.Write(ref _renderedCompanionSnapshot, _renderedCompanions.ToArray()); + Volatile.Write(ref _ownedObjectSnapshot, _ownedObjects.Keys.ToArray()); + Volatile.Write(ref _ownedObjectMapSnapshot, new Dictionary(_ownedObjects)); + } + + private void QueueFrameworkUpdate(Action action) + { + if (action == null) + return; + + if (_framework.IsInFrameworkUpdateThread) + { + action(); + return; + } + + _framework.RunOnFrameworkThread(action); + } + + private void DisposeHooks() + { + var hadHooks = _hooksActive + || _onInitializeHook is not null + || _onTerminateHook is not null + || _onDestructorHook is not null + || _onCompanionInitializeHook is not null + || _onCompanionTerminateHook is not null; + + _onInitializeHook?.Disable(); + _onTerminateHook?.Disable(); + _onDestructorHook?.Disable(); + _onCompanionInitializeHook?.Disable(); + _onCompanionTerminateHook?.Disable(); + + _onInitializeHook?.Dispose(); + _onTerminateHook?.Dispose(); + _onDestructorHook?.Dispose(); + _onCompanionInitializeHook?.Dispose(); + _onCompanionTerminateHook?.Dispose(); + + _onInitializeHook = null; + _onTerminateHook = null; + _onDestructorHook = null; + _onCompanionInitializeHook = null; + _onCompanionTerminateHook = null; + + _hooksActive = false; + + if (hadHooks) + { + _logger.LogDebug("ActorObjectService hooks disabled."); + } + } + + public void Dispose() + { + DisposeHooks(); + GC.SuppressFinalize(this); + } + + private static bool IsSupportedObjectKind(DalamudObjectKind objectKind) => + objectKind is DalamudObjectKind.Player + or DalamudObjectKind.BattleNpc + or DalamudObjectKind.Companion + or DalamudObjectKind.MountType; + + private static List EnumerateActiveCharacterAddresses() + { + var results = new List(64); + var manager = GameObjectManager.Instance(); + if (manager == null) + return results; + + const int objectLimit = 200; + + unsafe + { + for (var i = 0; i < objectLimit; i++) + { + Pointer objPtr = manager->Objects.IndexSorted[i]; + var obj = objPtr.Value; + if (obj == null) + continue; + + var objectKind = (DalamudObjectKind)obj->ObjectKind; + if (!IsSupportedObjectKind(objectKind)) + continue; + + results.Add((nint)obj); + } + } + + return results; + } +} diff --git a/LightlessSync/Services/BroadcastScanningService.cs b/LightlessSync/Services/BroadcastScanningService.cs index 95abdae..45f0fa1 100644 --- a/LightlessSync/Services/BroadcastScanningService.cs +++ b/LightlessSync/Services/BroadcastScanningService.cs @@ -1,7 +1,7 @@ -using Dalamud.Game.ClientState.Objects.SubKinds; -using Dalamud.Plugin.Services; +using Dalamud.Plugin.Services; using LightlessSync.API.Dto.User; using LightlessSync.LightlessConfiguration; +using LightlessSync.Services.ActorTracking; using LightlessSync.Services.Mediator; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; @@ -11,7 +11,7 @@ namespace LightlessSync.Services; public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDisposable { private readonly ILogger _logger; - private readonly IObjectTable _objectTable; + private readonly ActorObjectService _actorTracker; private readonly IFramework _framework; private readonly BroadcastService _broadcastService; @@ -40,17 +40,14 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos public readonly record struct BroadcastEntry(bool IsBroadcasting, DateTime ExpiryTime, string? GID); public BroadcastScannerService(ILogger logger, - IClientState clientState, - IObjectTable objectTable, IFramework framework, BroadcastService broadcastService, LightlessMediator mediator, NameplateHandler nameplateHandler, - DalamudUtilService dalamudUtil, - LightlessConfigService configService) : base(logger, mediator) + ActorObjectService actorTracker) : base(logger, mediator) { _logger = logger; - _objectTable = objectTable; + _actorTracker = actorTracker; _broadcastService = broadcastService; _nameplateHandler = nameplateHandler; @@ -76,12 +73,12 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos var now = DateTime.UtcNow; - foreach (var obj in _objectTable) + foreach (var address in _actorTracker.PlayerAddresses) { - if (obj is not IPlayerCharacter player || player.Address == IntPtr.Zero) + if (address == nint.Zero) continue; - var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer(player.Address); + var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer(address); var isStale = !_broadcastCache.TryGetValue(cid, out var entry) || entry.ExpiryTime <= now; if (isStale && _lookupQueuedCids.Add(cid) && _lookupQueue.Count < MaxQueueSize) @@ -237,6 +234,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos _framework.Update -= OnFrameworkUpdate; _cleanupCts.Cancel(); _cleanupTask?.Wait(100); + _cleanupCts.Dispose(); _nameplateHandler.Uninit(); } } diff --git a/LightlessSync/Services/CharaData/CharaDataManager.cs b/LightlessSync/Services/CharaData/CharaDataManager.cs index 38ec1c7..d8b2387 100644 --- a/LightlessSync/Services/CharaData/CharaDataManager.cs +++ b/LightlessSync/Services/CharaData/CharaDataManager.cs @@ -6,9 +6,9 @@ using LightlessSync.Interop.Ipc; using LightlessSync.LightlessConfiguration; using LightlessSync.PlayerData.Factories; using LightlessSync.PlayerData.Handlers; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.CharaData.Models; using LightlessSync.Services.Mediator; +using LightlessSync.UI.Services; using LightlessSync.Utils; using LightlessSync.WebAPI; using Microsoft.Extensions.Logging; @@ -28,7 +28,7 @@ public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase private readonly List _nearbyData = []; private readonly CharaDataNearbyManager _nearbyManager; private readonly CharaDataCharacterHandler _characterHandler; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly Dictionary _ownCharaData = []; private readonly Dictionary _sharedMetaInfoTimeoutTasks = []; private readonly Dictionary> _sharedWithYouData = []; @@ -45,7 +45,7 @@ public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase LightlessMediator lightlessMediator, IpcManager ipcManager, DalamudUtilService dalamudUtilService, FileDownloadManagerFactory fileDownloadManagerFactory, CharaDataConfigService charaDataConfigService, CharaDataNearbyManager charaDataNearbyManager, - CharaDataCharacterHandler charaDataCharacterHandler, PairManager pairManager) : base(logger, lightlessMediator) + CharaDataCharacterHandler charaDataCharacterHandler, PairUiService pairUiService) : base(logger, lightlessMediator) { _apiController = apiController; _fileHandler = charaDataFileHandler; @@ -54,7 +54,7 @@ public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase _configService = charaDataConfigService; _nearbyManager = charaDataNearbyManager; _characterHandler = charaDataCharacterHandler; - _pairManager = pairManager; + _pairUiService = pairUiService; lightlessMediator.Subscribe(this, (msg) => { _connectCts?.Cancel(); @@ -421,9 +421,10 @@ public sealed partial class CharaDataManager : DisposableMediatorSubscriberBase }); var result = await GetSharedWithYouTask.ConfigureAwait(false); + var snapshot = _pairUiService.GetSnapshot(); foreach (var grouping in result.GroupBy(r => r.Uploader)) { - var pair = _pairManager.GetPairByUID(grouping.Key.UID); + snapshot.PairsByUid.TryGetValue(grouping.Key.UID, out var pair); if (pair?.IsPaused ?? false) continue; List newList = new(); foreach (var item in grouping) diff --git a/LightlessSync/Services/CharacterAnalyzer.cs b/LightlessSync/Services/CharacterAnalyzer.cs index 27235f6..75c25d6 100644 --- a/LightlessSync/Services/CharacterAnalyzer.cs +++ b/LightlessSync/Services/CharacterAnalyzer.cs @@ -1,4 +1,4 @@ -using LightlessSync.API.Data; +using LightlessSync.API.Data; using LightlessSync.API.Data.Enum; using LightlessSync.FileCache; using LightlessSync.Services.Mediator; @@ -40,21 +40,16 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable public int TotalFiles { get; internal set; } internal Dictionary> LastAnalysis { get; } = []; public CharacterAnalysisSummary LatestSummary => _latestSummary; - public void CancelAnalyze() { _analysisCts?.CancelDispose(); _analysisCts = null; } - public async Task ComputeAnalysis(bool print = true, bool recalculate = false) { Logger.LogDebug("=== Calculating Character Analysis ==="); - _analysisCts = _analysisCts?.CancelRecreate() ?? new(); - var cancelToken = _analysisCts.Token; - var allFiles = LastAnalysis.SelectMany(v => v.Value.Select(d => d.Value)).ToList(); if (allFiles.Exists(c => !c.IsComputed || recalculate)) { @@ -62,7 +57,6 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable TotalFiles = remaining.Count; CurrentFile = 1; Logger.LogDebug("=== Computing {amount} remaining files ===", remaining.Count); - Mediator.Publish(new HaltScanMessage(nameof(CharacterAnalyzer))); try { @@ -72,9 +66,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable await file.ComputeSizes(_fileCacheManager, cancelToken).ConfigureAwait(false); CurrentFile++; } - _fileCacheManager.WriteOutFullCsv(); - } catch (Exception ex) { @@ -87,36 +79,49 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable } RecalculateSummary(); - Mediator.Publish(new CharacterDataAnalyzedMessage()); - _analysisCts.CancelDispose(); _analysisCts = null; - if (print) PrintAnalysis(); } - public void Dispose() { _analysisCts.CancelDispose(); } - + public async Task UpdateFileEntriesAsync(IEnumerable filePaths, CancellationToken token) + { + var normalized = new HashSet( + filePaths.Where(path => !string.IsNullOrWhiteSpace(path)), + StringComparer.OrdinalIgnoreCase); + if (normalized.Count == 0) + { + return; + } + foreach (var objectEntries in LastAnalysis.Values) + { + foreach (var entry in objectEntries.Values) + { + if (!entry.FilePaths.Any(path => normalized.Contains(path))) + { + continue; + } + token.ThrowIfCancellationRequested(); + await entry.ComputeSizes(_fileCacheManager, token).ConfigureAwait(false); + } + } + } private async Task BaseAnalysis(CharacterData charaData, CancellationToken token) { if (string.Equals(charaData.DataHash.Value, _lastDataHash, StringComparison.Ordinal)) return; - LastAnalysis.Clear(); - foreach (var obj in charaData.FileReplacements) { Dictionary data = new(StringComparer.OrdinalIgnoreCase); foreach (var fileEntry in obj.Value) { token.ThrowIfCancellationRequested(); - var fileCacheEntries = _fileCacheManager.GetAllFileCachesByHash(fileEntry.Hash, ignoreCacheEntries: true, validate: false).ToList(); if (fileCacheEntries.Count == 0) continue; - var filePath = fileCacheEntries[0].ResolvedFilepath; FileInfo fi = new(filePath); string ext = "unk?"; @@ -128,9 +133,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable { Logger.LogWarning(ex, "Could not identify extension for {path}", filePath); } - var tris = await _xivDataAnalyzer.GetTrianglesByHash(fileEntry.Hash).ConfigureAwait(false); - foreach (var entry in fileCacheEntries) { data[fileEntry.Hash] = new FileDataEntry(fileEntry.Hash, ext, @@ -141,17 +144,13 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable tris); } } - LastAnalysis[obj.Key] = data; } RecalculateSummary(); - Mediator.Publish(new CharacterDataAnalyzedMessage()); - _lastDataHash = charaData.DataHash.Value; } - private void RecalculateSummary() { var builder = ImmutableDictionary.CreateBuilder(); @@ -177,7 +176,6 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable _latestSummary = new CharacterAnalysisSummary(builder.ToImmutable()); } - private void PrintAnalysis() { if (LastAnalysis.Count == 0) return; @@ -186,7 +184,6 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable int fileCounter = 1; int totalFiles = kvp.Value.Count; Logger.LogInformation("=== Analysis for {obj} ===", kvp.Key); - foreach (var entry in kvp.Value.OrderBy(b => b.Value.GamePaths.OrderBy(p => p, StringComparer.Ordinal).First(), StringComparer.Ordinal)) { Logger.LogInformation("File {x}/{y}: {hash}", fileCounter++, totalFiles, entry.Key); @@ -215,7 +212,6 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable Logger.LogInformation("Total files: {count}, size extracted: {size}, size compressed: {sizeComp}", kvp.Value.Count, UiSharedService.ByteToString(kvp.Value.Sum(v => v.Value.OriginalSize)), UiSharedService.ByteToString(kvp.Value.Sum(v => v.Value.CompressedSize))); } - Logger.LogInformation("=== Total summary for all currently present objects ==="); Logger.LogInformation("Total files: {count}, size extracted: {size}, size compressed: {sizeComp}", LastAnalysis.Values.Sum(v => v.Values.Count), @@ -223,7 +219,6 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable UiSharedService.ByteToString(LastAnalysis.Values.Sum(c => c.Values.Sum(v => v.CompressedSize)))); Logger.LogInformation("IMPORTANT NOTES:\n\r- For Lightless up- and downloads only the compressed size is relevant.\n\r- An unusually high total files count beyond 200 and up will also increase your download time to others significantly."); } - internal sealed record FileDataEntry(string Hash, string FileType, List GamePaths, List FilePaths, long OriginalSize, long CompressedSize, long Triangles) { public bool IsComputed => OriginalSize > 0 && CompressedSize > 0; @@ -243,7 +238,6 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable public long OriginalSize { get; private set; } = OriginalSize; public long CompressedSize { get; private set; } = CompressedSize; public long Triangles { get; private set; } = Triangles; - public Lazy Format = new(() => { switch (FileType) diff --git a/LightlessSync/Services/Chat/ChatModels.cs b/LightlessSync/Services/Chat/ChatModels.cs new file mode 100644 index 0000000..f83a7e9 --- /dev/null +++ b/LightlessSync/Services/Chat/ChatModels.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using LightlessSync.API.Dto.Chat; + +namespace LightlessSync.Services.Chat; + +public sealed record ChatMessageEntry( + ChatMessageDto Payload, + string DisplayName, + bool FromSelf, + DateTime ReceivedAtUtc); + +public readonly record struct ChatChannelSnapshot( + string Key, + ChatChannelDescriptor Descriptor, + string DisplayName, + ChatChannelType Type, + bool IsConnected, + bool IsAvailable, + string? StatusText, + bool HasUnread, + int UnreadCount, + IReadOnlyList Messages); diff --git a/LightlessSync/Services/Chat/ZoneChatService.cs b/LightlessSync/Services/Chat/ZoneChatService.cs new file mode 100644 index 0000000..1aee611 --- /dev/null +++ b/LightlessSync/Services/Chat/ZoneChatService.cs @@ -0,0 +1,1131 @@ +using LightlessSync; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LightlessSync.API.Dto; +using LightlessSync.API.Dto.Chat; +using LightlessSync.Services; +using LightlessSync.Services.ActorTracking; +using LightlessSync.Services.Mediator; +using LightlessSync.WebAPI; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using LightlessSync.UI.Services; +using LightlessSync.LightlessConfiguration; + +namespace LightlessSync.Services.Chat; + +public sealed class ZoneChatService : DisposableMediatorSubscriberBase, IHostedService +{ + private const int MaxMessageHistory = 150; + internal const int MaxOutgoingLength = 400; + private const int MaxUnreadCount = 999; + private const string ZoneUnavailableMessage = "Zone chat is only available in major cities."; + private const string ZoneChannelKey = "zone"; + + private readonly ApiController _apiController; + private readonly ChatConfigService _chatConfigService; + private readonly DalamudUtilService _dalamudUtilService; + private readonly ActorObjectService _actorObjectService; + private readonly PairUiService _pairUiService; + + private readonly object _sync = new(); + + private readonly Dictionary _channels = new(StringComparer.Ordinal); + private readonly List _channelOrder = new(); + private readonly Dictionary _territoryToZoneKey = new(); + private readonly Dictionary _zoneDefinitions = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _groupDefinitions = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _lastReadCounts = new(StringComparer.Ordinal); + private readonly Dictionary _lastPresenceStates = new(StringComparer.Ordinal); + private readonly Dictionary _selfTokens = new(StringComparer.Ordinal); + private readonly List _pendingSelfMessages = new(); + + private bool _isLoggedIn; + private bool _isConnected; + private ChatChannelDescriptor? _lastZoneDescriptor; + private string? _activeChannelKey; + private bool _chatEnabled = false; + private bool _chatHandlerRegistered; + + public ZoneChatService( + ILogger logger, + LightlessMediator mediator, + ChatConfigService chatConfigService, + ApiController apiController, + DalamudUtilService dalamudUtilService, + ActorObjectService actorObjectService, + PairUiService pairUiService) + : base(logger, mediator) + { + _chatConfigService = chatConfigService; + _apiController = apiController; + _dalamudUtilService = dalamudUtilService; + _actorObjectService = actorObjectService; + _pairUiService = pairUiService; + + _isLoggedIn = _dalamudUtilService.IsLoggedIn; + _isConnected = _apiController.IsConnected; + _chatEnabled = _chatConfigService.Current.AutoEnableChatOnLogin; + } + + public IReadOnlyList GetChannelsSnapshot() + { + lock (_sync) + { + var snapshots = new List(_channelOrder.Count); + foreach (var key in _channelOrder) + { + if (!_channels.TryGetValue(key, out var state)) + continue; + + var statusText = state.StatusText; + if (!_chatEnabled) + { + statusText = "Chat services disabled"; + } + else if (!_isConnected) + { + statusText = "Disconnected from chat server"; + } + + snapshots.Add(new ChatChannelSnapshot( + state.Key, + state.Descriptor, + state.DisplayName, + state.Type, + state.IsConnected, + state.IsConnected && state.IsAvailable, + statusText, + state.HasUnread, + state.UnreadCount, + state.Messages.ToList())); + } + + return snapshots; + } + } + + public bool IsChatEnabled + { + get + { + lock (_sync) + { + return _chatEnabled; + } + } + } + + public bool IsChatConnected + { + get + { + lock (_sync) + { + return _chatEnabled && _isConnected; + } + } + } + + public void SetActiveChannel(string? key) + { + lock (_sync) + { + _activeChannelKey = key; + if (key is not null && _channels.TryGetValue(key, out var state)) + { + state.HasUnread = false; + state.UnreadCount = 0; + _lastReadCounts[key] = state.Messages.Count; + } + } + } + + public Task SetChatEnabledAsync(bool enabled) + => enabled ? EnableChatAsync() : DisableChatAsync(); + + private async Task EnableChatAsync() + { + bool wasEnabled; + lock (_sync) + { + wasEnabled = _chatEnabled; + if (!wasEnabled) + { + _chatEnabled = true; + } + } + + if (wasEnabled) + return; + + RegisterChatHandler(); + + await RefreshChatChannelDefinitionsAsync().ConfigureAwait(false); + ScheduleZonePresenceUpdate(force: true); + await EnsureGroupPresenceAsync(force: true).ConfigureAwait(false); + } + + private async Task DisableChatAsync() + { + bool wasEnabled; + List groupDescriptors; + ChatChannelDescriptor? zoneDescriptor; + + lock (_sync) + { + wasEnabled = _chatEnabled; + if (!wasEnabled) + { + return; + } + + _chatEnabled = false; + zoneDescriptor = _lastZoneDescriptor; + _lastZoneDescriptor = null; + + groupDescriptors = _channels.Values + .Where(state => state.Type == ChatChannelType.Group) + .Select(state => state.Descriptor) + .ToList(); + + _selfTokens.Clear(); + _pendingSelfMessages.Clear(); + + foreach (var state in _channels.Values) + { + state.IsConnected = false; + state.IsAvailable = false; + state.StatusText = "Chat services disabled"; + } + } + + UnregisterChatHandler(); + + if (zoneDescriptor.HasValue) + { + await SendPresenceAsync(zoneDescriptor.Value, 0, isActive: false, force: true).ConfigureAwait(false); + } + + foreach (var descriptor in groupDescriptors) + { + await SendPresenceAsync(descriptor, 0, isActive: false, force: true).ConfigureAwait(false); + } + + PublishChannelListChanged(); + } + + public async Task SendMessageAsync(ChatChannelDescriptor descriptor, string message) + { + if (!_chatEnabled) + return false; + + if (string.IsNullOrWhiteSpace(message)) + return false; + + var sanitized = message.Trim().ReplaceLineEndings(" "); + if (sanitized.Length == 0) + return false; + + if (sanitized.Length > MaxOutgoingLength) + sanitized = sanitized[..MaxOutgoingLength]; + + var pendingMessage = EnqueuePendingSelfMessage(descriptor, sanitized); + + try + { + await _apiController.SendChatMessage(new ChatSendRequestDto(descriptor, sanitized)).ConfigureAwait(false); + return true; + } + catch (Exception ex) + { + RemovePendingSelfMessage(pendingMessage); + Logger.LogWarning(ex, "Failed to send chat message"); + return false; + } + } + + public Task ResolveParticipantAsync(ChatChannelDescriptor descriptor, string token) + => _apiController.ResolveChatParticipant(new ChatParticipantResolveRequestDto(descriptor, token)); + + public Task StartAsync(CancellationToken cancellationToken) + { + Mediator.Subscribe(this, _ => HandleLogin()); + Mediator.Subscribe(this, _ => HandleLogout()); + Mediator.Subscribe(this, _ => ScheduleZonePresenceUpdate()); + Mediator.Subscribe(this, _ => ScheduleZonePresenceUpdate(force: true)); + Mediator.Subscribe(this, msg => HandleConnected(msg.Connection)); + Mediator.Subscribe(this, _ => HandleConnected(null)); + Mediator.Subscribe(this, _ => HandleReconnecting()); + Mediator.Subscribe(this, _ => HandleReconnecting()); + Mediator.Subscribe(this, _ => RefreshGroupsFromPairManager()); + Mediator.Subscribe(this, _ => ScheduleZonePresenceUpdate(force: true)); + + if (_chatEnabled) + { + RegisterChatHandler(); + _ = RefreshChatChannelDefinitionsAsync(); + ScheduleZonePresenceUpdate(force: true); + _ = EnsureGroupPresenceAsync(force: true); + } + else + { + UpdateChannelsForDisabledState(); + PublishChannelListChanged(); + } + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + UnregisterChatHandler(); + UnsubscribeAll(); + return Task.CompletedTask; + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + UnregisterChatHandler(); + UnsubscribeAll(); + } + + base.Dispose(disposing); + } + + private void HandleLogin() + { + _isLoggedIn = true; + if (_chatEnabled) + { + ScheduleZonePresenceUpdate(force: true); + _ = EnsureGroupPresenceAsync(force: true); + } + } + + private void HandleLogout() + { + _isLoggedIn = false; + if (_chatEnabled) + { + ScheduleZonePresenceUpdate(force: true); + } + } + + private void HandleConnected(ConnectionDto? connection) + { + _isConnected = true; + + lock (_sync) + { + _selfTokens.Clear(); + _pendingSelfMessages.Clear(); + + foreach (var state in _channels.Values) + { + state.IsConnected = _chatEnabled; + if (_chatEnabled && state.Type == ChatChannelType.Group) + { + state.IsAvailable = true; + state.StatusText = null; + } + else if (!_chatEnabled) + { + state.IsAvailable = false; + state.StatusText = "Chat services disabled"; + } + } + } + + PublishChannelListChanged(); + + if (_chatEnabled) + { + _ = RefreshChatChannelDefinitionsAsync(); + ScheduleZonePresenceUpdate(force: true); + _ = EnsureGroupPresenceAsync(force: true); + } + } + + private void HandleReconnecting() + { + _isConnected = false; + + lock (_sync) + { + _selfTokens.Clear(); + _pendingSelfMessages.Clear(); + foreach (var state in _channels.Values) + { + state.IsConnected = false; + if (_chatEnabled) + { + state.StatusText = "Disconnected from chat server"; + if (state.Type == ChatChannelType.Group) + { + state.IsAvailable = false; + } + } + else + { + state.StatusText = "Chat services disabled"; + state.IsAvailable = false; + } + } + } + + PublishChannelListChanged(); + } + + private async Task RefreshChatChannelDefinitionsAsync() + { + if (!_chatEnabled) + return; + + try + { + var zones = await _apiController.GetZoneChatChannelsAsync().ConfigureAwait(false); + var groups = await _apiController.GetGroupChatChannelsAsync().ConfigureAwait(false); + + ApplyZoneDefinitions(zones); + ApplyGroupDefinitions(groups); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to refresh chat channel definitions"); + } + } + + private void RegisterChatHandler() + { + if (_chatHandlerRegistered) + return; + + _apiController.RegisterChatMessageHandler(OnChatMessageReceived); + _chatHandlerRegistered = true; + } + + private void UnregisterChatHandler() + { + if (!_chatHandlerRegistered) + return; + + _apiController.UnregisterChatMessageHandler(OnChatMessageReceived); + _chatHandlerRegistered = false; + } + + private void UpdateChannelsForDisabledState() + { + lock (_sync) + { + foreach (var state in _channels.Values) + { + state.IsConnected = false; + state.IsAvailable = false; + state.StatusText = "Chat services disabled"; + } + } + } + + private void ScheduleZonePresenceUpdate(bool force = false) + { + if (!_chatEnabled) + return; + + _ = UpdateZonePresenceAsync(force); + } + + private async Task UpdateZonePresenceAsync(bool force = false) + { + if (!_chatEnabled) + return; + + if (!_isLoggedIn || !_apiController.IsConnected) + { + await LeaveCurrentZoneAsync(force, 0).ConfigureAwait(false); + return; + } + + try + { + var location = await _dalamudUtilService.GetMapDataAsync().ConfigureAwait(false); + var territoryId = (ushort)location.TerritoryId; + + string? zoneKey; + ZoneChannelDefinition? definition = null; + + lock (_sync) + { + _territoryToZoneKey.TryGetValue(territoryId, out zoneKey); + if (zoneKey is not null) + { + _zoneDefinitions.TryGetValue(zoneKey, out var def); + definition = def; + } + } + + if (definition is null) + { + await LeaveCurrentZoneAsync(force, territoryId).ConfigureAwait(false); + return; + } + + var descriptor = await BuildZoneDescriptorAsync(definition.Value).ConfigureAwait(false); + if (descriptor is null) + { + await LeaveCurrentZoneAsync(force, territoryId).ConfigureAwait(false); + return; + } + + bool shouldForceSend; + + lock (_sync) + { + var state = EnsureZoneStateLocked(); + state.DisplayName = definition.Value.DisplayName; + state.Descriptor = descriptor.Value; + state.IsConnected = _chatEnabled && _isConnected; + state.IsAvailable = _chatEnabled; + state.StatusText = _chatEnabled ? null : "Chat services disabled"; + + _activeChannelKey = ZoneChannelKey; + shouldForceSend = force || !_lastZoneDescriptor.HasValue || !ChannelDescriptorsMatch(_lastZoneDescriptor.Value, descriptor.Value); + _lastZoneDescriptor = descriptor; + } + + PublishChannelListChanged(); + await SendPresenceAsync(descriptor.Value, territoryId, isActive: true, force: shouldForceSend).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to update zone chat presence"); + } + } + + private async Task LeaveCurrentZoneAsync(bool force, ushort territoryId) + { + ChatChannelDescriptor? descriptor = null; + bool clearedHistory = false; + + lock (_sync) + { + descriptor = _lastZoneDescriptor; + _lastZoneDescriptor = null; + + if (_channels.TryGetValue(ZoneChannelKey, out var state)) + { + if (state.Messages.Count > 0) + { + state.Messages.Clear(); + state.HasUnread = false; + state.UnreadCount = 0; + _lastReadCounts[ZoneChannelKey] = 0; + clearedHistory = true; + } + + state.IsConnected = _isConnected; + state.IsAvailable = false; + state.StatusText = !_chatEnabled + ? "Chat services disabled" + : (_isConnected ? ZoneUnavailableMessage : "Disconnected from chat server"); + state.DisplayName = "Zone Chat"; + } + + if (_activeChannelKey == ZoneChannelKey) + { + _activeChannelKey = _channelOrder.FirstOrDefault(key => key != ZoneChannelKey); + } + } + + if (clearedHistory) + { + PublishHistoryCleared(ZoneChannelKey); + } + + PublishChannelListChanged(); + + if (descriptor.HasValue) + { + await SendPresenceAsync(descriptor.Value, territoryId, isActive: false, force: force).ConfigureAwait(false); + } + } + + private async Task BuildZoneDescriptorAsync(ZoneChannelDefinition definition) + { + try + { + var worldId = (ushort)await _dalamudUtilService.GetWorldIdAsync().ConfigureAwait(false); + return definition.Descriptor with { WorldId = worldId }; + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to obtain world id for zone chat"); + return null; + } + } + + private void ApplyZoneDefinitions(IReadOnlyList? infos) + { + var infoList = infos ?? Array.Empty(); + + lock (_sync) + { + _zoneDefinitions.Clear(); + _territoryToZoneKey.Clear(); + + foreach (var info in infoList) + { + var descriptor = info.Channel.WithNormalizedCustomKey(); + var key = descriptor.CustomKey ?? string.Empty; + if (string.IsNullOrWhiteSpace(key)) + continue; + + var territories = info.Territories? + .SelectMany(EnumerateTerritoryKeys) + .Where(n => n.Length > 0) + .ToHashSet(StringComparer.OrdinalIgnoreCase) + ?? new HashSet(StringComparer.OrdinalIgnoreCase); + + _zoneDefinitions[key] = new ZoneChannelDefinition(key, info.DisplayName ?? key, descriptor, territories); + } + + var territoryData = _dalamudUtilService.TerritoryData.Value; + foreach (var kvp in territoryData) + { + foreach (var variant in EnumerateTerritoryKeys(kvp.Value)) + { + foreach (var def in _zoneDefinitions.Values) + { + if (def.TerritoryNames.Contains(variant)) + { + _territoryToZoneKey[(uint)kvp.Key] = def.Key; + break; + } + } + } + } + + if (_zoneDefinitions.Count == 0) + { + RemoveZoneStateLocked(); + } + else + { + var state = EnsureZoneStateLocked(); + state.DisplayName = "Zone Chat"; + state.IsConnected = _chatEnabled && _isConnected; + state.IsAvailable = false; + state.StatusText = _chatEnabled ? ZoneUnavailableMessage : "Chat services disabled"; + } + + UpdateChannelOrderLocked(); + } + + PublishChannelListChanged(); + } + + private void ApplyGroupDefinitions(IReadOnlyList? infos) + { + var infoList = infos ?? Array.Empty(); + var descriptorsToJoin = new List(); + var descriptorsToLeave = new List(); + + lock (_sync) + { + var remainingGroups = new HashSet(_groupDefinitions.Keys, StringComparer.OrdinalIgnoreCase); + + foreach (var info in infoList) + { + var descriptor = info.Channel.WithNormalizedCustomKey(); + var groupId = info.GroupId; + if (string.IsNullOrWhiteSpace(groupId)) + continue; + + remainingGroups.Remove(groupId); + + _groupDefinitions[groupId] = new GroupChannelDefinition(groupId, info.DisplayName ?? groupId, descriptor, info.IsOwner); + + var key = BuildChannelKey(descriptor); + if (!_channels.TryGetValue(key, out var state)) + { + state = new ChatChannelState(key, ChatChannelType.Group, info.DisplayName ?? groupId, descriptor); + state.IsConnected = _chatEnabled && _isConnected; + state.IsAvailable = _chatEnabled && _isConnected; + state.StatusText = !_chatEnabled + ? "Chat services disabled" + : (_isConnected ? null : "Disconnected from chat server"); + _channels[key] = state; + _lastReadCounts[key] = 0; + if (_chatEnabled) + { + descriptorsToJoin.Add(descriptor); + } + } + else + { + state.DisplayName = info.DisplayName ?? groupId; + state.Descriptor = descriptor; + state.IsConnected = _chatEnabled && _isConnected; + state.IsAvailable = _chatEnabled && _isConnected; + state.StatusText = !_chatEnabled + ? "Chat services disabled" + : (_isConnected ? null : "Disconnected from chat server"); + } + } + + foreach (var removedGroupId in remainingGroups) + { + if (_groupDefinitions.TryGetValue(removedGroupId, out var definition)) + { + var key = BuildChannelKey(definition.Descriptor); + if (_channels.TryGetValue(key, out var state)) + { + descriptorsToLeave.Add(state.Descriptor); + _channels.Remove(key); + _lastReadCounts.Remove(key); + _lastPresenceStates.Remove(BuildPresenceKey(state.Descriptor)); + _selfTokens.Remove(key); + _pendingSelfMessages.RemoveAll(p => string.Equals(p.ChannelKey, key, StringComparison.Ordinal)); + if (string.Equals(_activeChannelKey, key, StringComparison.Ordinal)) + { + _activeChannelKey = null; + } + } + + _groupDefinitions.Remove(removedGroupId); + } + } + + UpdateChannelOrderLocked(); + } + + foreach (var descriptor in descriptorsToLeave) + { + _ = SendPresenceAsync(descriptor, 0, isActive: false, force: true); + } + + foreach (var descriptor in descriptorsToJoin) + { + _ = SendPresenceAsync(descriptor, 0, isActive: true, force: true); + } + + PublishChannelListChanged(); + } + + private void RefreshGroupsFromPairManager() + { + var snapshot = _pairUiService.GetSnapshot(); + var groups = snapshot.Groups.ToList(); + if (groups.Count == 0) + { + ApplyGroupDefinitions(Array.Empty()); + return; + } + + var infos = new List(groups.Count); + foreach (var group in groups) + { + var descriptor = new ChatChannelDescriptor + { + Type = ChatChannelType.Group, + WorldId = 0, + ZoneId = 0, + CustomKey = group.Group.GID + }; + + var displayName = string.IsNullOrWhiteSpace(group.Group.Alias) ? group.Group.GID : group.Group.Alias; + var isOwner = string.Equals(group.Owner.UID, _apiController.UID, StringComparison.Ordinal); + + infos.Add(new GroupChatChannelInfoDto(descriptor, displayName, group.Group.GID, isOwner)); + } + + ApplyGroupDefinitions(infos); + } + + private async Task EnsureGroupPresenceAsync(bool force = false) + { + if (!_chatEnabled) + return; + + List descriptors; + lock (_sync) + { + descriptors = _channels.Values + .Where(state => state.Type == ChatChannelType.Group) + .Select(state => state.Descriptor) + .ToList(); + } + + foreach (var descriptor in descriptors) + { + await SendPresenceAsync(descriptor, 0, isActive: true, force: force).ConfigureAwait(false); + } + } + + private async Task SendPresenceAsync(ChatChannelDescriptor descriptor, ushort territoryId, bool isActive, bool force) + { + if (!_apiController.IsConnected) + return; + + if (!_chatEnabled && isActive) + return; + + var presenceKey = BuildPresenceKey(descriptor); + bool stateMatches; + + lock (_sync) + { + stateMatches = !force + && _lastPresenceStates.TryGetValue(presenceKey, out var lastState) + && lastState == isActive; + } + + if (stateMatches) + return; + + try + { + await _apiController.UpdateChatPresence(new ChatPresenceUpdateDto(descriptor, territoryId, isActive)).ConfigureAwait(false); + + lock (_sync) + { + if (isActive) + { + _lastPresenceStates[presenceKey] = true; + } + else + { + _lastPresenceStates.Remove(presenceKey); + } + } + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to update chat presence"); + } + } + + private PendingSelfMessage EnqueuePendingSelfMessage(ChatChannelDescriptor descriptor, string message) + { + var normalized = descriptor.WithNormalizedCustomKey(); + var key = normalized.Type == ChatChannelType.Zone ? ZoneChannelKey : BuildChannelKey(normalized); + var pending = new PendingSelfMessage(key, message); + + lock (_sync) + { + _pendingSelfMessages.Add(pending); + while (_pendingSelfMessages.Count > 20) + { + _pendingSelfMessages.RemoveAt(0); + } + } + + return pending; + } + + private void RemovePendingSelfMessage(PendingSelfMessage pending) + { + lock (_sync) + { + var index = _pendingSelfMessages.FindIndex(p => + string.Equals(p.ChannelKey, pending.ChannelKey, StringComparison.Ordinal) && + string.Equals(p.Message, pending.Message, StringComparison.Ordinal)); + + if (index >= 0) + { + _pendingSelfMessages.RemoveAt(index); + } + } + } + + private void OnChatMessageReceived(ChatMessageDto dto) + { + var descriptor = dto.Channel.WithNormalizedCustomKey(); + var key = descriptor.Type == ChatChannelType.Zone ? ZoneChannelKey : BuildChannelKey(descriptor); + var fromSelf = IsMessageFromSelf(dto, key); + var message = BuildMessage(dto, fromSelf); + bool publishChannelList = false; + + lock (_sync) + { + if (!_channels.TryGetValue(key, out var state)) + { + var displayName = descriptor.Type switch + { + ChatChannelType.Zone => _zoneDefinitions.TryGetValue(descriptor.CustomKey ?? string.Empty, out var def) + ? def.DisplayName + : "Zone Chat", + ChatChannelType.Group => descriptor.CustomKey ?? "Syncshell", + _ => descriptor.CustomKey ?? "Chat" + }; + + state = new ChatChannelState( + key, + descriptor.Type, + displayName, + descriptor.Type == ChatChannelType.Zone ? (_lastZoneDescriptor ?? descriptor) : descriptor); + + state.IsConnected = _isConnected; + state.IsAvailable = descriptor.Type == ChatChannelType.Group && _isConnected; + state.StatusText = descriptor.Type == ChatChannelType.Zone ? ZoneUnavailableMessage : (_isConnected ? null : "Disconnected from chat server"); + + _channels[key] = state; + _lastReadCounts[key] = 0; + publishChannelList = true; + } + + state.Descriptor = descriptor.Type == ChatChannelType.Zone ? (_lastZoneDescriptor ?? descriptor) : descriptor; + state.Messages.Add(message); + if (state.Messages.Count > MaxMessageHistory) + { + state.Messages.RemoveAt(0); + } + + if (string.Equals(_activeChannelKey, key, StringComparison.Ordinal)) + { + state.HasUnread = false; + state.UnreadCount = 0; + _lastReadCounts[key] = state.Messages.Count; + } + else + { + var lastRead = _lastReadCounts.TryGetValue(key, out var readCount) ? readCount : 0; + var unreadFromHistory = Math.Max(0, state.Messages.Count - lastRead); + var incrementalUnread = Math.Min(state.UnreadCount + 1, MaxUnreadCount); + state.UnreadCount = Math.Min(Math.Max(unreadFromHistory, incrementalUnread), MaxUnreadCount); + state.HasUnread = state.UnreadCount > 0; + } + } + + Mediator.Publish(new ChatChannelMessageAdded(key, message)); + + if (publishChannelList) + { + lock (_sync) + { + UpdateChannelOrderLocked(); + } + + PublishChannelListChanged(); + } + } + + private bool IsMessageFromSelf(ChatMessageDto dto, string channelKey) + { + if (dto.Sender.User?.UID is { } uid && string.Equals(uid, _apiController.UID, StringComparison.Ordinal)) + { + lock (_sync) + { + _selfTokens[channelKey] = dto.Sender.Token; + } + + return true; + } + + lock (_sync) + { + if (_selfTokens.TryGetValue(channelKey, out var token) && + string.Equals(token, dto.Sender.Token, StringComparison.Ordinal)) + { + return true; + } + + var index = _pendingSelfMessages.FindIndex(p => + string.Equals(p.ChannelKey, channelKey, StringComparison.Ordinal) && + string.Equals(p.Message, dto.Message, StringComparison.Ordinal)); + + if (index >= 0) + { + _pendingSelfMessages.RemoveAt(index); + _selfTokens[channelKey] = dto.Sender.Token; + return true; + } + } + + return false; + } + + private ChatMessageEntry BuildMessage(ChatMessageDto dto, bool fromSelf) + { + var displayName = ResolveDisplayName(dto, fromSelf); + return new ChatMessageEntry(dto, displayName, fromSelf, DateTime.UtcNow); + } + + private string ResolveDisplayName(ChatMessageDto dto, bool fromSelf) + { + var isZone = dto.Channel.Type == ChatChannelType.Zone; + if (!string.IsNullOrEmpty(dto.Sender.HashedCid) && + _actorObjectService.TryGetActorByHash(dto.Sender.HashedCid, out var descriptor) && + !string.IsNullOrWhiteSpace(descriptor.Name)) + { + return descriptor.Name; + } + + if (fromSelf && isZone && dto.Sender.CanResolveProfile) + { + try + { + return _dalamudUtilService.GetPlayerNameAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Failed to resolve self name for chat message"); + } + } + + if (dto.Sender.Kind == ChatSenderKind.IdentifiedUser && dto.Sender.User is not null) + { + return dto.Sender.User.AliasOrUID; + } + + if (!string.IsNullOrWhiteSpace(dto.Sender.DisplayName)) + { + return dto.Sender.DisplayName!; + } + + return dto.Sender.Token; + } + + private void UpdateChannelOrderLocked() + { + _channelOrder.Clear(); + + if (_channels.ContainsKey(ZoneChannelKey)) + { + _channelOrder.Add(ZoneChannelKey); + } + + var groups = _channels.Values + .Where(state => state.Type == ChatChannelType.Group) + .OrderBy(state => state.DisplayName, StringComparer.OrdinalIgnoreCase) + .Select(state => state.Key); + + _channelOrder.AddRange(groups); + + if (_activeChannelKey is null && _channelOrder.Count > 0) + { + _activeChannelKey = _channelOrder[0]; + } + else if (_activeChannelKey is not null && !_channelOrder.Contains(_activeChannelKey)) + { + _activeChannelKey = _channelOrder.Count > 0 ? _channelOrder[0] : null; + } + } + + private void PublishChannelListChanged() => Mediator.Publish(new ChatChannelsUpdated()); + + private void PublishHistoryCleared(string channelKey) => Mediator.Publish(new ChatChannelHistoryCleared(channelKey)); + + private static IEnumerable EnumerateTerritoryKeys(string? value) + { + if (string.IsNullOrWhiteSpace(value)) + yield break; + + var normalizedFull = NormalizeKey(value); + if (normalizedFull.Length > 0) + yield return normalizedFull; + + var segments = value.Split('-', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); + if (segments.Length <= 1) + yield break; + + for (var i = 1; i < segments.Length; i++) + { + var composite = string.Join(" - ", segments[i..]); + var normalized = NormalizeKey(composite); + if (normalized.Length > 0) + yield return normalized; + } + } + + private static string NormalizeKey(string? value) + => string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim().ToUpperInvariant(); + + private static string BuildChannelKey(ChatChannelDescriptor descriptor) + => $"{(int)descriptor.Type}:{NormalizeKey(descriptor.CustomKey)}"; + + private static string BuildPresenceKey(ChatChannelDescriptor descriptor) + => $"{(int)descriptor.Type}:{descriptor.WorldId}:{NormalizeKey(descriptor.CustomKey)}"; + + private static bool ChannelDescriptorsMatch(ChatChannelDescriptor left, ChatChannelDescriptor right) + => left.Type == right.Type + && NormalizeKey(left.CustomKey) == NormalizeKey(right.CustomKey) + && left.WorldId == right.WorldId; + + private ChatChannelState EnsureZoneStateLocked() + { + if (!_channels.TryGetValue(ZoneChannelKey, out var state)) + { + state = new ChatChannelState(ZoneChannelKey, ChatChannelType.Zone, "Zone Chat", new ChatChannelDescriptor { Type = ChatChannelType.Zone }); + state.IsConnected = _chatEnabled && _isConnected; + state.IsAvailable = false; + state.StatusText = _chatEnabled ? ZoneUnavailableMessage : "Chat services disabled"; + _channels[ZoneChannelKey] = state; + _lastReadCounts[ZoneChannelKey] = 0; + UpdateChannelOrderLocked(); + } + + return state; + } + + private void RemoveZoneStateLocked() + { + if (_channels.Remove(ZoneChannelKey)) + { + _lastReadCounts.Remove(ZoneChannelKey); + _lastPresenceStates.Remove(BuildPresenceKey(new ChatChannelDescriptor { Type = ChatChannelType.Zone })); + _selfTokens.Remove(ZoneChannelKey); + _pendingSelfMessages.RemoveAll(p => string.Equals(p.ChannelKey, ZoneChannelKey, StringComparison.Ordinal)); + if (string.Equals(_activeChannelKey, ZoneChannelKey, StringComparison.Ordinal)) + { + _activeChannelKey = null; + } + UpdateChannelOrderLocked(); + } + } + + private sealed class ChatChannelState + { + public ChatChannelState(string key, ChatChannelType type, string displayName, ChatChannelDescriptor descriptor) + { + Key = key; + Type = type; + DisplayName = displayName; + Descriptor = descriptor; + Messages = new List(); + } + + public string Key { get; } + public ChatChannelType Type { get; } + public string DisplayName { get; set; } + public ChatChannelDescriptor Descriptor { get; set; } + public bool IsConnected { get; set; } + public bool IsAvailable { get; set; } + public string? StatusText { get; set; } + public bool HasUnread { get; set; } + public int UnreadCount { get; set; } + public List Messages { get; } + } + + private readonly record struct ZoneChannelDefinition( + string Key, + string DisplayName, + ChatChannelDescriptor Descriptor, + HashSet TerritoryNames); + + private readonly record struct GroupChannelDefinition( + string GroupId, + string DisplayName, + ChatChannelDescriptor Descriptor, + bool IsOwner); + + private readonly record struct PendingSelfMessage(string ChannelKey, string Message); +} + + + diff --git a/LightlessSync/Services/ContextMenuService.cs b/LightlessSync/Services/ContextMenuService.cs index 464fee1..075a704 100644 --- a/LightlessSync/Services/ContextMenuService.cs +++ b/LightlessSync/Services/ContextMenuService.cs @@ -1,12 +1,15 @@ +using LightlessSync; using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.Gui.ContextMenu; using Dalamud.Plugin; using Dalamud.Plugin.Services; using LightlessSync.LightlessConfiguration; -using LightlessSync.PlayerData.Pairs; +using LightlessSync.LightlessConfiguration.Models; +using LightlessSync.Services.Mediator; using LightlessSync.Utils; using LightlessSync.WebAPI; using Lumina.Excel.Sheets; +using LightlessSync.UI.Services; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -20,11 +23,15 @@ internal class ContextMenuService : IHostedService private readonly ILogger _logger; private readonly DalamudUtilService _dalamudUtil; private readonly IClientState _clientState; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly PairRequestService _pairRequestService; private readonly ApiController _apiController; private readonly IObjectTable _objectTable; private readonly LightlessConfigService _configService; + private readonly BroadcastScannerService _broadcastScannerService; + private readonly BroadcastService _broadcastService; + private readonly LightlessProfileManager _lightlessProfileManager; + private readonly LightlessMediator _mediator; public ContextMenuService( IContextMenu contextMenu, @@ -36,8 +43,12 @@ internal class ContextMenuService : IHostedService IObjectTable objectTable, LightlessConfigService configService, PairRequestService pairRequestService, - PairManager pairManager, - IClientState clientState) + PairUiService pairUiService, + IClientState clientState, + BroadcastScannerService broadcastScannerService, + BroadcastService broadcastService, + LightlessProfileManager lightlessProfileManager, + LightlessMediator mediator) { _contextMenu = contextMenu; _pluginInterface = pluginInterface; @@ -47,9 +58,13 @@ internal class ContextMenuService : IHostedService _apiController = apiController; _objectTable = objectTable; _configService = configService; - _pairManager = pairManager; + _pairUiService = pairUiService; _pairRequestService = pairRequestService; _clientState = clientState; + _broadcastScannerService = broadcastScannerService; + _broadcastService = broadcastService; + _lightlessProfileManager = lightlessProfileManager; + _mediator = mediator; } public Task StartAsync(CancellationToken cancellationToken) @@ -78,42 +93,67 @@ internal class ContextMenuService : IHostedService private void OnMenuOpened(IMenuOpenedArgs args) { - if (!_pluginInterface.UiBuilder.ShouldModifyUi) return; if (args.AddonName != null) return; - - //Check if target is not menutargetdefault. + if (args.Target is not MenuTargetDefault target) return; - //Check if name or target id isnt null/zero if (string.IsNullOrEmpty(target.TargetName) || target.TargetObjectId == 0 || target.TargetHomeWorld.RowId == 0) return; - //Check if it is a real target. IPlayerCharacter? targetData = GetPlayerFromObjectTable(target); if (targetData == null || targetData.Address == nint.Zero) return; - //Check if user is directly paired or is own. - if (VisibleUserIds.Any(u => u == target.TargetObjectId) || _clientState.LocalPlayer.GameObjectId == target.TargetObjectId) + if (!_configService.Current.EnableRightClickMenus) + return; + + var snapshot = _pairUiService.GetSnapshot(); + var pair = snapshot.PairsByUid.Values.FirstOrDefault(p => + p.IsVisible && + p.PlayerCharacterId != uint.MaxValue && + (ulong)p.PlayerCharacterId == target.TargetObjectId); + + if (pair is not null) + { + pair.AddContextMenu(args); + return; + } + + //Check if user is directly paired or is own. + if (VisibleUserIds.Contains(target.TargetObjectId) || (_clientState.LocalPlayer?.GameObjectId ?? 0) == target.TargetObjectId) return; - //Check if in PVP or GPose if (_clientState.IsPvPExcludingDen || _clientState.IsGPosing) return; - //Check for valid world. var world = GetWorld(target.TargetHomeWorld.RowId); if (!IsWorldValid(world)) return; - if (!_configService.Current.EnableRightClickMenus) - return; - + string? targetHashedCid = null; + if (_broadcastService.IsBroadcasting) + { + targetHashedCid = DalamudUtilService.GetHashedCIDFromPlayerPointer(targetData.Address); + } + + if (!string.IsNullOrEmpty(targetHashedCid) && CanOpenLightfinderProfile(targetHashedCid)) + { + var hashedCid = targetHashedCid; + args.AddMenuItem(new MenuItem + { + Name = "Open Lightless Profile", + PrefixChar = 'L', + UseDefaultPrefix = false, + PrefixColor = 708, + OnClicked = async _ => await HandleLightfinderProfileSelection(hashedCid!).ConfigureAwait(false) + }); + } + args.AddMenuItem(new MenuItem { Name = "Send Direct Pair Request", @@ -124,6 +164,12 @@ internal class ContextMenuService : IHostedService }); } + private HashSet VisibleUserIds => + _pairUiService.GetSnapshot().PairsByUid.Values + .Where(p => p.IsVisible && p.PlayerCharacterId != uint.MaxValue) + .Select(p => (ulong)p.PlayerCharacterId) + .ToHashSet(); + private async Task HandleSelection(IMenuArgs args) { if (args.Target is not MenuTargetDefault target) @@ -159,9 +205,48 @@ internal class ContextMenuService : IHostedService } } - private HashSet VisibleUserIds => [.. _pairManager.DirectPairs - .Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue) - .Select(u => (ulong)u.PlayerCharacterId)]; + private async Task HandleLightfinderProfileSelection(string hashedCid) + { + if (string.IsNullOrWhiteSpace(hashedCid)) + return; + + if (!_broadcastService.IsBroadcasting) + { + Notify("Lightfinder inactive", "Enable Lightfinder to open broadcaster profiles.", NotificationType.Warning, 6); + return; + } + + if (!_broadcastScannerService.BroadcastCache.TryGetValue(hashedCid, out var entry) || !entry.IsBroadcasting || entry.ExpiryTime <= DateTime.UtcNow) + { + Notify("Broadcaster unavailable", "That player is not currently using Lightfinder.", NotificationType.Info, 5); + return; + } + + var result = await _lightlessProfileManager.GetLightfinderProfileAsync(hashedCid).ConfigureAwait(false); + if (result == null) + { + Notify("Profile unavailable", "Unable to load Lightless profile for that player.", NotificationType.Error, 6); + return; + } + + _mediator.Publish(new OpenLightfinderProfileMessage(result.Value.User, result.Value.ProfileData, hashedCid)); + } + + private void Notify(string title, string message, NotificationType type, double durationSeconds) + { + _mediator.Publish(new NotificationMessage(title, message, type, TimeSpan.FromSeconds(durationSeconds))); + } + + private bool CanOpenLightfinderProfile(string hashedCid) + { + if (!_broadcastService.IsBroadcasting) + return false; + + if (!_broadcastScannerService.BroadcastCache.TryGetValue(hashedCid, out var entry)) + return false; + + return entry.IsBroadcasting && entry.ExpiryTime > DateTime.UtcNow; + } private IPlayerCharacter? GetPlayerFromObjectTable(MenuTargetDefault target) { diff --git a/LightlessSync/Services/DalamudUtilService.cs b/LightlessSync/Services/DalamudUtilService.cs index e5fd735..716523d 100644 --- a/LightlessSync/Services/DalamudUtilService.cs +++ b/LightlessSync/Services/DalamudUtilService.cs @@ -12,15 +12,20 @@ using FFXIVClientStructs.FFXIV.Client.UI.Agent; using LightlessSync.API.Dto.CharaData; using LightlessSync.Interop; using LightlessSync.LightlessConfiguration; +using LightlessSync.PlayerData.Factories; using LightlessSync.PlayerData.Handlers; +using LightlessSync.PlayerData.Pairs; +using LightlessSync.Services.ActorTracking; using LightlessSync.Services.Mediator; using LightlessSync.Utils; using Lumina.Excel.Sheets; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Text; +using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject; namespace LightlessSync.Services; @@ -37,23 +42,24 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber private readonly IGameGui _gameGui; private readonly ILogger _logger; private readonly IObjectTable _objectTable; + private readonly ActorObjectService _actorObjectService; private readonly PerformanceCollectorService _performanceCollector; private readonly LightlessConfigService _configService; private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; + private readonly Lazy _pairFactory; private uint? _classJobId = 0; private DateTime _delayedFrameworkUpdateCheck = DateTime.UtcNow; private string _lastGlobalBlockPlayer = string.Empty; private string _lastGlobalBlockReason = string.Empty; private ushort _lastZone = 0; - private readonly Dictionary _playerCharas = new(StringComparer.Ordinal); - private readonly List _notUpdatedCharas = []; + private ushort _lastWorldId = 0; private bool _sentBetweenAreas = false; private Lazy _cid; public DalamudUtilService(ILogger logger, IClientState clientState, IObjectTable objectTable, IFramework framework, IGameGui gameGui, ICondition condition, IDataManager gameData, ITargetManager targetManager, IGameConfig gameConfig, - BlockedCharacterHandler blockedCharacterHandler, LightlessMediator mediator, PerformanceCollectorService performanceCollector, - LightlessConfigService configService, PlayerPerformanceConfigService playerPerformanceConfigService) + ActorObjectService actorObjectService, BlockedCharacterHandler blockedCharacterHandler, LightlessMediator mediator, PerformanceCollectorService performanceCollector, + LightlessConfigService configService, PlayerPerformanceConfigService playerPerformanceConfigService, Lazy pairFactory) { _logger = logger; _clientState = clientState; @@ -63,11 +69,13 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber _condition = condition; _gameData = gameData; _gameConfig = gameConfig; + _actorObjectService = actorObjectService; _blockedCharacterHandler = blockedCharacterHandler; Mediator = mediator; _performanceCollector = performanceCollector; _configService = configService; _playerPerformanceConfigService = playerPerformanceConfigService; + _pairFactory = pairFactory; WorldData = new(() => { return gameData.GetExcelSheet(Dalamud.Game.ClientLanguage.English)! @@ -119,9 +127,12 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber mediator.Subscribe(this, (msg) => { if (clientState.IsPvP) return; - var name = msg.Pair.PlayerName; + var pair = _pairFactory.Value.Create(msg.Pair.UniqueIdent) ?? msg.Pair; + var name = pair.PlayerName; if (string.IsNullOrEmpty(name)) return; - var addr = _playerCharas.FirstOrDefault(f => string.Equals(f.Value.Name, name, StringComparison.Ordinal)).Value.Address; + if (!_actorObjectService.TryGetPlayerByName(name, out var descriptor)) + return; + var addr = descriptor.Address; if (addr == nint.Zero) return; var useFocusTarget = _configService.Current.UseFocusTarget; _ = RunOnFrameworkThread(() => @@ -194,7 +205,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber { EnsureIsOnFramework(); var objTableObj = _objectTable[index]; - if (objTableObj!.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) return null; + if (objTableObj!.ObjectKind != DalamudObjectKind.Player) return null; return (ICharacter)objTableObj; } @@ -226,7 +237,13 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public IEnumerable GetGposeCharactersFromObjectTable() { - return _objectTable.Where(o => o.ObjectIndex > 200 && o.ObjectKind == Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player).Cast(); + foreach (var actor in _actorObjectService.PlayerDescriptors + .Where(a => a.ObjectKind == DalamudObjectKind.Player && a.ObjectIndex > 200)) + { + var character = _objectTable.CreateObjectReference(actor.Address) as ICharacter; + if (character != null) + yield return character; + } } public bool GetIsPlayerPresent() @@ -281,7 +298,8 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public IntPtr GetPlayerCharacterFromCachedTableByIdent(string characterName) { - if (_playerCharas.TryGetValue(characterName, out var pchar)) return pchar.Address; + if (_actorObjectService.TryGetActorByHash(characterName, out var actor)) + return actor.Address; return IntPtr.Zero; } @@ -552,8 +570,12 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber internal (string Name, nint Address) FindPlayerByNameHash(string ident) { - _playerCharas.TryGetValue(ident, out var result); - return result; + if (_actorObjectService.TryGetActorByHash(ident, out var descriptor)) + { + return (descriptor.Name, descriptor.Address); + } + + return default; } public string? GetWorldNameFromPlayerAddress(nint address) @@ -639,37 +661,43 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber _performanceCollector.LogPerformance(this, $"FrameworkOnUpdateInternal+{(isNormalFrameworkUpdate ? "Regular" : "Delayed")}", () => { IsAnythingDrawing = false; - _performanceCollector.LogPerformance(this, $"ObjTableToCharas", + _performanceCollector.LogPerformance(this, $"TrackedActorsToState", () => { - _notUpdatedCharas.AddRange(_playerCharas.Keys); + _actorObjectService.RefreshTrackedActors(); - for (int i = 0; i < 200; i += 2) + var playerDescriptors = _actorObjectService.PlayerCharacterDescriptors; + for (var i = 0; i < playerDescriptors.Count; i++) { - var chara = _objectTable[i]; - if (chara == null || chara.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) + var actor = playerDescriptors[i]; + + var playerAddress = actor.Address; + if (playerAddress == nint.Zero) continue; - if (_blockedCharacterHandler.IsCharacterBlocked(chara.Address, out bool firstTime) && firstTime) + if (actor.ObjectIndex >= 200) + continue; + + if (_blockedCharacterHandler.IsCharacterBlocked(playerAddress, out bool firstTime) && firstTime) { - _logger.LogTrace("Skipping character {addr}, blocked/muted", chara.Address.ToString("X")); + _logger.LogTrace("Skipping character {addr}, blocked/muted", playerAddress.ToString("X")); continue; } - var charaName = ((GameObject*)chara.Address)->NameString; - var hash = GetHashedCIDFromPlayerPointer(chara.Address); if (!IsAnythingDrawing) - CheckCharacterForDrawing(chara.Address, charaName); - _notUpdatedCharas.Remove(hash); - _playerCharas[hash] = (charaName, chara.Address); + { + var gameObj = (GameObject*)playerAddress; + var currentName = gameObj != null ? gameObj->NameString ?? string.Empty : string.Empty; + var charaName = string.IsNullOrEmpty(currentName) ? actor.Name : currentName; + CheckCharacterForDrawing(playerAddress, charaName); + if (IsAnythingDrawing) + break; + } + else + { + break; + } } - - foreach (var notUpdatedChara in _notUpdatedCharas) - { - _playerCharas.Remove(notUpdatedChara); - } - - _notUpdatedCharas.Clear(); }); if (!IsAnythingDrawing && !string.IsNullOrEmpty(_lastGlobalBlockPlayer)) @@ -786,6 +814,18 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber if (localPlayer != null) { _classJobId = localPlayer.ClassJob.RowId; + + var currentWorldId = (ushort)localPlayer.CurrentWorld.RowId; + if (currentWorldId != _lastWorldId) + { + var previousWorldId = _lastWorldId; + _lastWorldId = currentWorldId; + Mediator.Publish(new WorldChangedMessage(previousWorldId, currentWorldId)); + } + } + else if (_lastWorldId != 0) + { + _lastWorldId = 0; } if (!IsInCombat || !IsPerforming || !IsInInstance) @@ -801,6 +841,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber _logger.LogDebug("Logged in"); IsLoggedIn = true; _lastZone = _clientState.TerritoryType; + _lastWorldId = (ushort)localPlayer.CurrentWorld.RowId; _cid = RebuildCID(); Mediator.Publish(new DalamudLoginMessage()); } @@ -808,6 +849,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber { _logger.LogDebug("Logged out"); IsLoggedIn = false; + _lastWorldId = 0; Mediator.Publish(new DalamudLogoutMessage()); } diff --git a/LightlessSync/Services/LightlessGroupProfileData.cs b/LightlessSync/Services/LightlessGroupProfileData.cs index 1b27b40..eb77175 100644 --- a/LightlessSync/Services/LightlessGroupProfileData.cs +++ b/LightlessSync/Services/LightlessGroupProfileData.cs @@ -1,6 +1,20 @@ -namespace LightlessSync.Services; +using System; +using System.Collections.Generic; -public record LightlessGroupProfileData(string Base64ProfilePicture, string Description, int[] Tags, bool IsNsfw, bool IsDisabled) +namespace LightlessSync.Services; + +public record LightlessGroupProfileData( + bool IsDisabled, + bool IsNsfw, + string Base64ProfilePicture, + string Base64BannerPicture, + string Description, + IReadOnlyList Tags) { - public Lazy ImageData { get; } = new Lazy(Convert.FromBase64String(Base64ProfilePicture)); + public Lazy ProfileImageData { get; } = new(() => ConvertSafe(Base64ProfilePicture)); + public Lazy BannerImageData { get; } = new(() => ConvertSafe(Base64BannerPicture)); + + private static byte[] ConvertSafe(string value) => string.IsNullOrEmpty(value) + ? Array.Empty() + : Convert.FromBase64String(value); } diff --git a/LightlessSync/Services/LightlessProfileData.cs b/LightlessSync/Services/LightlessProfileData.cs new file mode 100644 index 0000000..ef62862 --- /dev/null +++ b/LightlessSync/Services/LightlessProfileData.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace LightlessSync.Services; + +public record LightlessProfileData( + bool IsFlagged, + bool IsNSFW, + string Base64ProfilePicture, + string Base64SupporterPicture, + string Base64BannerPicture, + string Description, + IReadOnlyList Tags) +{ + public Lazy ImageData { get; } = new(() => ConvertSafe(Base64ProfilePicture)); + public Lazy SupporterImageData { get; } = new(() => ConvertSafe(Base64SupporterPicture)); + public Lazy BannerImageData { get; } = new(() => ConvertSafe(Base64BannerPicture)); + + private static byte[] ConvertSafe(string value) => string.IsNullOrEmpty(value) ? Array.Empty() : Convert.FromBase64String(value); +} diff --git a/LightlessSync/Services/LightlessProfileManager.cs b/LightlessSync/Services/LightlessProfileManager.cs index 00b610b..0895078 100644 --- a/LightlessSync/Services/LightlessProfileManager.cs +++ b/LightlessSync/Services/LightlessProfileManager.cs @@ -1,10 +1,12 @@ -using LightlessSync.API.Data; +using LightlessSync.API.Data; using LightlessSync.API.Data.Comparer; +using LightlessSync.API.Dto.User; using LightlessSync.LightlessConfiguration; using LightlessSync.Services.Mediator; using LightlessSync.WebAPI; using Microsoft.Extensions.Logging; using Serilog.Core; +using System; using System.Collections.Concurrent; namespace LightlessSync.Services; @@ -15,7 +17,8 @@ public class LightlessProfileManager : MediatorSubscriberBase private const string _lightlessLogo = "iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGlmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgOS4xLWMwMDIgNzkuZGJhM2RhMywgMjAyMy8xMi8xMy0wNTowNjo0OSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI2LjggKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyNS0wOC0zMFQwMDo1MTozNCswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyNS0wOC0zMFQwMjoxMjo0MiswMjowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjUtMDgtMzBUMDI6MTI6NDIrMDI6MDAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Y2JjY2YwZDctNTU4ZS1kYzQ1LTk0MmQtZTg5YWE5ZWRhYjUzIiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6Nzk1NDcwMjYtYjM2OC1jMjRhLTliYzEtYmQzMjE4OTJlN2FiIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MGRiOTU0NTktM2E2OS0xNDQ2LWFmYmMtM2M4ODhjZDUxYmU0IiBkYzpmb3JtYXQ9ImltYWdlL3BuZyIgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyI+IDx4bXBNTTpIaXN0b3J5PiA8cmRmOlNlcT4gPHJkZjpsaSBzdEV2dDphY3Rpb249ImNyZWF0ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MGRiOTU0NTktM2E2OS0xNDQ2LWFmYmMtM2M4ODhjZDUxYmU0IiBzdEV2dDp3aGVuPSIyMDI1LTA4LTMwVDAwOjUxOjM0KzAxOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjYuOCAoV2luZG93cykiLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmE5OWYwOGE5LTgxNDItY2E0Mi04MmY1LTM2MjZmOTgzNDZhYiIgc3RFdnQ6d2hlbj0iMjAyNS0wOC0zMFQwMDo1MTozNCswMTowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDI2LjggKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpjYmNjZjBkNy01NThlLWRjNDUtOTQyZC1lODlhYTllZGFiNTMiIHN0RXZ0OndoZW49IjIwMjUtMDgtMzBUMDI6MTI6NDIrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyNS43IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5CIHRlAAEVd0lEQVR42uz9d7xtWVXmD3/HnHOttcPJ5+ZYOVAUFDlnEBQwKybs1jaDoj9b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"; private const string _lightlessLogoLoading = "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"; private const string _lightlessLogoNsfw = "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"; - private const string _lightlessSupporter = "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"; + private const string _lightlessSupporter = "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"; + private const string _lightlessBanner = "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"; private const string _noUserDescription = "-- User has no description set --"; private const string _noGroupDescription = "-- Syncshell has no description set --"; private const string _nsfwDescription = "Profile not displayed - NSFW"; @@ -26,12 +29,78 @@ public class LightlessProfileManager : MediatorSubscriberBase private readonly ConcurrentDictionary _lightlessUserProfiles = new(UserDataComparer.Instance); private readonly ConcurrentDictionary _lightlessGroupProfiles = new(GroupDataComparer.Instance); - private readonly LightlessUserProfileData _defaultProfileUserData = new(IsFlagged: false, IsNSFW: false, _lightlessLogo, string.Empty, _noUserDescription); - private readonly LightlessUserProfileData _loadingProfileUserData = new(IsFlagged: false, IsNSFW: false, _lightlessLogoLoading, string.Empty, _loadingData); - private readonly LightlessGroupProfileData _loadingProfileGroupData = new(_lightlessLogoLoading, _loadingData, [], IsNsfw: false, IsDisabled: false); - private readonly LightlessGroupProfileData _defaultProfileGroupData = new(_lightlessLogo, _noGroupDescription, [], IsNsfw: false, IsDisabled: false); - private readonly LightlessUserProfileData _nsfwProfileUserData = new(IsFlagged: false, IsNSFW: true, _lightlessLogoNsfw, string.Empty, _nsfwDescription); - private readonly LightlessGroupProfileData _nsfwProfileGroupData = new(_lightlessLogoNsfw, _nsfwDescription, [], IsNsfw: false, IsDisabled: false); + private static readonly int[] _emptyTagSet = Array.Empty(); + private readonly LightlessUserProfileData _defaultProfileUserData = new( + IsFlagged: false, + IsNSFW: false, + Base64ProfilePicture: _lightlessLogo, + Base64SupporterPicture: string.Empty, + Base64BannerPicture: _lightlessBanner, + Description: _noUserDescription, + Tags: _emptyTagSet); + private readonly LightlessUserProfileData _loadingProfileUserData = new( + IsFlagged: false, + IsNSFW: false, + Base64ProfilePicture: _lightlessLogoLoading, + Base64SupporterPicture: string.Empty, + Base64BannerPicture: _lightlessBanner, + Description: _loadingData, + Tags: _emptyTagSet); + private readonly LightlessGroupProfileData _loadingProfileGroupData = new( + IsDisabled: false, + IsNsfw: false, + Base64ProfilePicture: _lightlessLogoLoading, + Base64BannerPicture: _lightlessBanner, + Description: _loadingData, + Tags: _emptyTagSet); + private readonly LightlessGroupProfileData _defaultProfileGroupData = new( + IsDisabled: false, + IsNsfw: false, + Base64ProfilePicture: _lightlessLogo, + Base64BannerPicture: _lightlessBanner, + Description: _noGroupDescription, + Tags: _emptyTagSet); + private readonly LightlessUserProfileData _nsfwProfileUserData = new( + IsFlagged: false, + IsNSFW: true, + Base64ProfilePicture: _lightlessLogoNsfw, + Base64SupporterPicture: string.Empty, + Base64BannerPicture: string.Empty, + Description: _nsfwDescription, + Tags: _emptyTagSet); + private readonly LightlessGroupProfileData _nsfwProfileGroupData = new( + IsDisabled: false, + IsNsfw: true, + Base64ProfilePicture: _lightlessLogoNsfw, + Base64BannerPicture: string.Empty, + Description: _nsfwDescription, + Tags: _emptyTagSet); + private const string _noDescription = "-- Profile has no description set --"; + private readonly ConcurrentDictionary _lightlessProfiles = new(UserDataComparer.Instance); + private readonly LightlessProfileData _defaultProfileData = new( + IsFlagged: false, + IsNSFW: false, + Base64ProfilePicture: _lightlessLogo, + Base64SupporterPicture: string.Empty, + Base64BannerPicture: _lightlessBanner, + Description: _noDescription, + Tags: _emptyTagSet); + private readonly LightlessProfileData _loadingProfileData = new( + IsFlagged: false, + IsNSFW: false, + Base64ProfilePicture: _lightlessLogoLoading, + Base64SupporterPicture: string.Empty, + Base64BannerPicture: _lightlessBanner, + Description: _loadingData, + Tags: _emptyTagSet); + private readonly LightlessProfileData _nsfwProfileData = new( + IsFlagged: false, + IsNSFW: false, + Base64ProfilePicture: _lightlessLogoNsfw, + Base64SupporterPicture: string.Empty, + Base64BannerPicture: string.Empty, + Description: _nsfwDescription, + Tags: _emptyTagSet); public LightlessProfileManager(ILogger logger, LightlessConfigService lightlessConfigService, LightlessMediator mediator, ApiController apiController) : base(logger, mediator) @@ -46,11 +115,13 @@ public class LightlessProfileManager : MediatorSubscriberBase { _logger.LogTrace("Received Clear Profile for User profile {data}", msg.UserData.AliasOrUID); _lightlessUserProfiles.Remove(msg.UserData, out _); + _lightlessProfiles.Remove(msg.UserData, out _); } else { _logger.LogTrace("Received Clear Profile for all User profiles"); _lightlessUserProfiles.Clear(); + _lightlessProfiles.Clear(); } }); @@ -74,6 +145,7 @@ public class LightlessProfileManager : MediatorSubscriberBase _logger.LogTrace("Received Disconnect, Clearing Profiles"); _lightlessUserProfiles.Clear(); _lightlessGroupProfiles.Clear(); + _lightlessProfiles.Clear(); } ); } @@ -95,6 +167,18 @@ public class LightlessProfileManager : MediatorSubscriberBase return (profile); } + public LightlessProfileData GetLightlessProfile(UserData data) + { + if (!_lightlessProfiles.TryGetValue(data, out var profile)) + { + _logger.LogTrace("Requesting Lightless profile for {data}", data); + _ = Task.Run(() => GetLightlessProfileFromService(data)); + return _loadingProfileData; + } + + return profile; + } + /// /// Fetches Group Profile from cache or API @@ -124,21 +208,32 @@ public class LightlessProfileManager : MediatorSubscriberBase { _logger.LogTrace("Inputting loading data in _lightlessUserProfiles for User {data}", data.AliasOrUID); _lightlessUserProfiles[data] = _loadingProfileUserData; + _lightlessProfiles[data] = _loadingProfileData; var profile = await _apiController.UserGetProfile(new API.Dto.User.UserDto(data)).ConfigureAwait(false); - - LightlessUserProfileData profileUserData = new(profile.Disabled, profile.IsNSFW ?? false, - string.IsNullOrEmpty(profile.ProfilePictureBase64) ? _lightlessLogo : profile.ProfilePictureBase64, - !string.IsNullOrEmpty(data.Alias) && !string.Equals(data.Alias, data.UID, StringComparison.Ordinal) ? _lightlessSupporter : string.Empty, - string.IsNullOrEmpty(profile.Description) ? _noUserDescription : profile.Description); + var tags = profile.Tags ?? _emptyTagSet; + var profileData = BuildProfileData(data, profile, tags); + var supporterImage = !string.IsNullOrEmpty(data.Alias) && !string.Equals(data.Alias, data.UID, StringComparison.Ordinal) + ? _lightlessSupporter + : string.Empty; + LightlessUserProfileData profileUserData = new( + IsFlagged: profile.Disabled, + IsNSFW: profile.IsNSFW ?? false, + Base64ProfilePicture: string.IsNullOrEmpty(profile.ProfilePictureBase64) ? _lightlessLogo : profile.ProfilePictureBase64, + Base64SupporterPicture: supporterImage, + Base64BannerPicture: string.IsNullOrEmpty(profile.BannerPictureBase64) ? _lightlessBanner : profile.BannerPictureBase64, + Description: string.IsNullOrEmpty(profile.Description) ? _noUserDescription : profile.Description, + Tags: tags); _logger.LogTrace("Replacing data in _lightlessUserProfiles for User {data}", data.AliasOrUID); if (profileUserData.IsNSFW && !_lightlessConfigService.Current.ProfilesAllowNsfw && !string.Equals(_apiController.UID, data.UID, StringComparison.Ordinal)) { _lightlessUserProfiles[data] = _nsfwProfileUserData; + _lightlessProfiles[data] = _nsfwProfileData; } else { _lightlessUserProfiles[data] = profileUserData; + _lightlessProfiles[data] = profileData; } } catch (Exception ex) @@ -146,6 +241,7 @@ public class LightlessProfileManager : MediatorSubscriberBase // if fails save DefaultProfileData to dict Logger.LogWarning(ex, "Failed to get Profile from service for user {user}", data); _lightlessUserProfiles[data] = _defaultProfileUserData; + _lightlessProfiles[data] = _defaultProfileData; } } @@ -161,14 +257,15 @@ public class LightlessProfileManager : MediatorSubscriberBase _logger.LogTrace("Inputting loading data in _lightlessGroupProfiles for Group {data}", data.AliasOrGID); _lightlessGroupProfiles[data] = _loadingProfileGroupData; var profile = await _apiController.GroupGetProfile(new API.Dto.Group.GroupDto(data)).ConfigureAwait(false); + var tags = profile.Tags ?? _emptyTagSet; LightlessGroupProfileData profileGroupData = new( + IsDisabled: profile.IsDisabled ?? false, + IsNsfw: profile.IsNsfw ?? false, Base64ProfilePicture: string.IsNullOrEmpty(profile.PictureBase64) ? _lightlessLogo : profile.PictureBase64, + Base64BannerPicture: string.IsNullOrEmpty(profile.BannerBase64) ? _lightlessBanner : profile.BannerBase64, Description: string.IsNullOrEmpty(profile.Description) ? _noGroupDescription : profile.Description, - Tags: profile.Tags ?? [], - profile.IsNsfw ?? false, - profile.IsDisabled ?? false - ); + Tags: tags); _logger.LogTrace("Replacing data in _lightlessGroupProfiles for Group {data}", data.AliasOrGID); if (profileGroupData.IsNsfw && !_lightlessConfigService.Current.ProfilesAllowNsfw) @@ -179,7 +276,6 @@ public class LightlessProfileManager : MediatorSubscriberBase { _lightlessGroupProfiles[data] = profileGroupData; } - _lightlessGroupProfiles[data] = profileGroupData; } catch (Exception ex) { @@ -188,4 +284,51 @@ public class LightlessProfileManager : MediatorSubscriberBase _lightlessGroupProfiles[data] = _defaultProfileGroupData; } } + + private LightlessProfileData BuildProfileData(UserData data, UserProfileDto profile, IReadOnlyList tags) + { + var supporterImage = !string.IsNullOrEmpty(data.Alias) && !string.Equals(data.Alias, data.UID, StringComparison.Ordinal) + ? _lightlessSupporter + : string.Empty; + var profileData = new LightlessProfileData( + IsFlagged: profile.Disabled, + IsNSFW: profile.IsNSFW ?? false, + Base64ProfilePicture: string.IsNullOrEmpty(profile.ProfilePictureBase64) ? _lightlessLogo : profile.ProfilePictureBase64, + Base64SupporterPicture: supporterImage, + Base64BannerPicture: string.IsNullOrEmpty(profile.BannerPictureBase64) ? _lightlessBanner : profile.BannerPictureBase64, + Description: string.IsNullOrEmpty(profile.Description) ? _noDescription : profile.Description, + Tags: tags); + + if (profileData.IsNSFW && !_lightlessConfigService.Current.ProfilesAllowNsfw && !string.Equals(_apiController.UID, data.UID, StringComparison.Ordinal)) + { + return _nsfwProfileData; + } + + return profileData; + } + + public async Task<(UserData User, LightlessProfileData ProfileData)?> GetLightfinderProfileAsync(string hashedCid) + { + if (string.IsNullOrWhiteSpace(hashedCid)) + return null; + + try + { + var profile = await _apiController.UserGetLightfinderProfile(hashedCid).ConfigureAwait(false); + if (profile == null) + return null; + + var userData = profile.User; + var profileTags = profile.Tags ?? _emptyTagSet; + var profileData = BuildProfileData(userData, profile, profileTags); + _lightlessProfiles[userData] = profileData; + + return (userData, profileData); + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Failed to get Lightfinder profile for CID {HashedCid}", hashedCid); + return null; + } + } } \ No newline at end of file diff --git a/LightlessSync/Services/LightlessUserProfileData.cs b/LightlessSync/Services/LightlessUserProfileData.cs index 3319043..b4ba383 100644 --- a/LightlessSync/Services/LightlessUserProfileData.cs +++ b/LightlessSync/Services/LightlessUserProfileData.cs @@ -1,7 +1,20 @@ -namespace LightlessSync.Services; +using System; +using System.Collections.Generic; -public record LightlessUserProfileData(bool IsFlagged, bool IsNSFW, string Base64ProfilePicture, string Base64SupporterPicture, string Description) +namespace LightlessSync.Services; + +public record LightlessUserProfileData( + bool IsFlagged, + bool IsNSFW, + string Base64ProfilePicture, + string Base64SupporterPicture, + string Base64BannerPicture, + string Description, + IReadOnlyList Tags) { - public Lazy ImageData { get; } = new Lazy(Convert.FromBase64String(Base64ProfilePicture)); - public Lazy SupporterImageData { get; } = new Lazy(string.IsNullOrEmpty(Base64SupporterPicture) ? [] : Convert.FromBase64String(Base64SupporterPicture)); + public Lazy ImageData { get; } = new(() => ConvertSafe(Base64ProfilePicture)); + public Lazy SupporterImageData { get; } = new(() => ConvertSafe(Base64SupporterPicture)); + public Lazy BannerImageData { get; } = new(() => ConvertSafe(Base64BannerPicture)); + + private static byte[] ConvertSafe(string value) => string.IsNullOrEmpty(value) ? Array.Empty() : Convert.FromBase64String(value); } diff --git a/LightlessSync/Services/Mediator/Messages.cs b/LightlessSync/Services/Mediator/Messages.cs index 79434c2..ef31cec 100644 --- a/LightlessSync/Services/Mediator/Messages.cs +++ b/LightlessSync/Services/Mediator/Messages.cs @@ -6,9 +6,12 @@ using LightlessSync.API.Dto.Group; using LightlessSync.LightlessConfiguration.Models; using LightlessSync.PlayerData.Handlers; using LightlessSync.PlayerData.Pairs; +using LightlessSync.Services.ActorTracking; +using LightlessSync.Services.Chat; using LightlessSync.Services.Events; using LightlessSync.WebAPI.Files.Models; using System.Numerics; +using LightlessSync.UI.Models; namespace LightlessSync.Services.Mediator; @@ -20,12 +23,15 @@ public record OpenSettingsUiMessage : MessageBase; public record OpenLightfinderSettingsMessage : MessageBase; public record DalamudLoginMessage : MessageBase; public record DalamudLogoutMessage : MessageBase; +public record ActorTrackedMessage(ActorObjectService.ActorDescriptor Descriptor) : SameThreadMessage; +public record ActorUntrackedMessage(ActorObjectService.ActorDescriptor Descriptor) : SameThreadMessage; public record PriorityFrameworkUpdateMessage : SameThreadMessage; public record FrameworkUpdateMessage : SameThreadMessage; public record ClassJobChangedMessage(GameObjectHandler GameObjectHandler) : MessageBase; public record DelayedFrameworkUpdateMessage : SameThreadMessage; public record ZoneSwitchStartMessage : MessageBase; public record ZoneSwitchEndMessage : MessageBase; +public record WorldChangedMessage(ushort PreviousWorldId, ushort CurrentWorldId) : MessageBase; public record CutsceneStartMessage : MessageBase; public record GposeStartMessage : SameThreadMessage; public record GposeEndMessage : MessageBase; @@ -65,6 +71,7 @@ public record HubReconnectingMessage(Exception? Exception) : SameThreadMessage; public record HubReconnectedMessage(string? Arg) : SameThreadMessage; public record HubClosedMessage(Exception? Exception) : SameThreadMessage; public record ResumeScanMessage(string Source) : MessageBase; +public record FileCacheInitializedMessage : MessageBase; public record DownloadReadyMessage(Guid RequestId) : MessageBase; public record DownloadStartedMessage(GameObjectHandler DownloadId, Dictionary DownloadStatus) : MessageBase; public record DownloadFinishedMessage(GameObjectHandler DownloadId) : MessageBase; @@ -72,11 +79,18 @@ public record UiToggleMessage(Type UiType) : MessageBase; public record PlayerUploadingMessage(GameObjectHandler Handler, bool IsUploading) : MessageBase; public record ClearProfileUserDataMessage(UserData? UserData = null) : MessageBase; public record ClearProfileGroupDataMessage(GroupData? GroupData = null) : MessageBase; -public record CyclePauseMessage(UserData UserData) : MessageBase; +public record CyclePauseMessage(Pair Pair) : MessageBase; public record PauseMessage(UserData UserData) : MessageBase; public record ProfilePopoutToggle(Pair? Pair) : MessageBase; public record CompactUiChange(Vector2 Size, Vector2 Position) : MessageBase; public record ProfileOpenStandaloneMessage(Pair Pair) : MessageBase; +public record GroupProfileOpenStandaloneMessage(GroupFullInfoDto Group) : MessageBase; +public record OpenGroupProfileEditorMessage(GroupFullInfoDto Group) : MessageBase; +public record CloseGroupProfilePreviewMessage(GroupFullInfoDto Group) : MessageBase; +public record ActiveServerChangedMessage(string ServerUrl) : MessageBase; +public record OpenSelfProfilePreviewMessage(UserData User) : MessageBase; +public record CloseSelfProfilePreviewMessage(UserData User) : MessageBase; +public record OpenLightfinderProfileMessage(UserData User, LightlessProfileData ProfileData, string HashedCid) : MessageBase; public record RemoveWindowMessage(WindowMediatorSubscriberBase Window) : MessageBase; public record RefreshUiMessage : MessageBase; public record OpenBanUserPopupMessage(Pair PairToBan, GroupFullInfoDto GroupFullInfoDto) : MessageBase; @@ -85,6 +99,8 @@ public record OpenSyncshellAdminPanel(GroupFullInfoDto GroupInfo) : MessageBase; public record OpenPermissionWindow(Pair Pair) : MessageBase; public record DownloadLimitChangedMessage() : SameThreadMessage; public record PairProcessingLimitChangedMessage : SameThreadMessage; +public record PairDataChangedMessage : MessageBase; +public record PairUiUpdatedMessage(PairUiSnapshot Snapshot) : MessageBase; public record CensusUpdateMessage(byte Gender, byte RaceId, byte TribeId) : MessageBase; public record TargetPairMessage(Pair Pair) : MessageBase; public record CombatStartMessage : MessageBase; @@ -112,5 +128,10 @@ public record PairRequestReceivedMessage(string HashedCid, string Message) : Mes public record PairRequestsUpdatedMessage : MessageBase; public record PairDownloadStatusMessage(List<(string PlayerName, float Progress, string Status)> DownloadStatus, int QueueWaiting) : MessageBase; public record VisibilityChange : MessageBase; +public record ChatChannelsUpdated : MessageBase; +public record ChatChannelMessageAdded(string ChannelKey, ChatMessageEntry Message) : MessageBase; +public record ChatChannelHistoryCleared(string ChannelKey) : MessageBase; +public record GroupCollectionChangedMessage : MessageBase; +public record OpenUserProfileMessage(UserData User) : MessageBase; #pragma warning restore S2094 #pragma warning restore MA0048 // File name must match type name \ No newline at end of file diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index 11af974..313eabe 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -7,9 +7,9 @@ using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; using LightlessSync.LightlessConfiguration; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.UI; +using LightlessSync.UI.Services; using LightlessSync.Utils; using LightlessSync.UtilsEnum.Enum; @@ -30,7 +30,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber private readonly IClientState _clientState; private readonly DalamudUtilService _dalamudUtil; private readonly LightlessConfigService _configService; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly LightlessMediator _mediator; public LightlessMediator Mediator => _mediator; @@ -51,7 +51,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber private ImmutableHashSet _activeBroadcastingCids = []; - public NameplateHandler(ILogger logger, IAddonLifecycle addonLifecycle, IGameGui gameGui, DalamudUtilService dalamudUtil, LightlessConfigService configService, LightlessMediator mediator, IClientState clientState, PairManager pairManager) + public NameplateHandler(ILogger logger, IAddonLifecycle addonLifecycle, IGameGui gameGui, DalamudUtilService dalamudUtil, LightlessConfigService configService, LightlessMediator mediator, IClientState clientState, PairUiService pairUiService) { _logger = logger; _addonLifecycle = addonLifecycle; @@ -60,7 +60,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber _configService = configService; _mediator = mediator; _clientState = clientState; - _pairManager = pairManager; + _pairUiService = pairUiService; System.Array.Fill(_cachedNameplateTextOffsets, int.MinValue); } @@ -493,7 +493,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber int centrePos = (nameplateWidth - nodeWidth) / 2; int staticMargin = 24; int calcMargin = (int)(nameplateWidth * 0.08f); - + switch (config.LabelAlignment) { case LabelAlignment.Left: @@ -515,7 +515,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber positionX = 58 + config.LightfinderLabelOffsetX; alignment = AlignmentType.Bottom; } - + positionY += config.LightfinderLabelOffsetY; alignment = (AlignmentType)System.Math.Clamp((int)alignment, 0, 8); @@ -533,7 +533,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber pNode->EdgeColor.B = (byte)(edgeColor.Z * 255); pNode->EdgeColor.A = (byte)(edgeColor.W * 255); - + if(!config.LightfinderLabelUseIcon) { pNode->AlignmentType = AlignmentType.Bottom; @@ -551,7 +551,7 @@ public unsafe class NameplateHandler : IMediatorSubscriber pNode->CharSpacing = 1; pNode->TextFlags = config.LightfinderLabelUseIcon ? TextFlags.Edge | TextFlags.Glare | TextFlags.AutoAdjustNodeSize - : TextFlags.Edge | TextFlags.Glare; + : TextFlags.Edge | TextFlags.Glare; } } @@ -653,8 +653,8 @@ public unsafe class NameplateHandler : IMediatorSubscriber var nameplateObject = GetNameplateObject(i); return nameplateObject != null ? nameplateObject.Value.RootComponentNode : null; } - - private HashSet VisibleUserIds => [.. _pairManager.GetOnlineUserPairs() + private HashSet VisibleUserIds + => [.. _pairUiService.GetSnapshot().PairsByUid.Values .Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue) .Select(u => (ulong)u.PlayerCharacterId)]; diff --git a/LightlessSync/Services/NameplateService.cs b/LightlessSync/Services/NameplateService.cs index 8ccc362..84b6d64 100644 --- a/LightlessSync/Services/NameplateService.cs +++ b/LightlessSync/Services/NameplateService.cs @@ -4,9 +4,9 @@ using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Services; using Dalamud.Utility; using LightlessSync.LightlessConfiguration; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.UI; +using LightlessSync.UI.Services; using Microsoft.Extensions.Logging; namespace LightlessSync.Services; @@ -17,20 +17,20 @@ public class NameplateService : DisposableMediatorSubscriberBase private readonly LightlessConfigService _configService; private readonly IClientState _clientState; private readonly INamePlateGui _namePlateGui; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; public NameplateService(ILogger logger, LightlessConfigService configService, INamePlateGui namePlateGui, IClientState clientState, - PairManager pairManager, + PairUiService pairUiService, LightlessMediator lightlessMediator) : base(logger, lightlessMediator) { _logger = logger; _configService = configService; _namePlateGui = namePlateGui; _clientState = clientState; - _pairManager = pairManager; + _pairUiService = pairUiService; _namePlateGui.OnNamePlateUpdate += OnNamePlateUpdate; _namePlateGui.RequestRedraw(); @@ -42,7 +42,8 @@ public class NameplateService : DisposableMediatorSubscriberBase if (!_configService.Current.IsNameplateColorsEnabled || (_configService.Current.IsNameplateColorsEnabled && _clientState.IsPvPExcludingDen)) return; - var visibleUsersIds = _pairManager.GetOnlineUserPairs() + var snapshot = _pairUiService.GetSnapshot(); + var visibleUsersIds = snapshot.PairsByUid.Values .Where(u => u.IsVisible && u.PlayerCharacterId != uint.MaxValue) .Select(u => (ulong)u.PlayerCharacterId) .ToHashSet(); @@ -74,7 +75,7 @@ public class NameplateService : DisposableMediatorSubscriberBase bool hasActualFcTag = playerCharacter.CompanyTag.TextValue.Length > 0; bool isFromDifferentRealm = playerCharacter.HomeWorld.RowId != playerCharacter.CurrentWorld.RowId; bool shouldColorFcArea = hasActualFcTag || (!hasActualFcTag && isFromDifferentRealm); - + if (shouldColorFcArea) { handler.FreeCompanyTagParts.OuterWrap = CreateTextWrap(colors); diff --git a/LightlessSync/Services/NotificationService.cs b/LightlessSync/Services/NotificationService.cs index 8709710..cb1a607 100644 --- a/LightlessSync/Services/NotificationService.cs +++ b/LightlessSync/Services/NotificationService.cs @@ -4,9 +4,14 @@ using Dalamud.Interface.ImGuiNotification; using Dalamud.Plugin.Services; using LightlessSync.LightlessConfiguration; using LightlessSync.LightlessConfiguration.Models; +using LightlessSync; +using LightlessSync.PlayerData.Factories; +using LightlessSync.PlayerData.Pairs; +using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.UI; using LightlessSync.UI.Models; +using LightlessSync.UI.Services; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using FFXIVClientStructs.FFXIV.Client.UI; @@ -24,6 +29,8 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ private readonly IChatGui _chatGui; private readonly PairRequestService _pairRequestService; private readonly HashSet _shownPairRequestNotifications = new(); + private readonly PairUiService _pairUiService; + private readonly PairFactory _pairFactory; public NotificationService( ILogger logger, @@ -32,7 +39,9 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ INotificationManager notificationManager, IChatGui chatGui, LightlessMediator mediator, - PairRequestService pairRequestService) : base(logger, mediator) + PairRequestService pairRequestService, + PairUiService pairUiService, + PairFactory pairFactory) : base(logger, mediator) { _logger = logger; _configService = configService; @@ -40,6 +49,8 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ _notificationManager = notificationManager; _chatGui = chatGui; _pairRequestService = pairRequestService; + _pairUiService = pairUiService; + _pairFactory = pairFactory; } public Task StartAsync(CancellationToken cancellationToken) @@ -391,6 +402,17 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ _logger.LogWarning(ex, "Failed to play notification sound effect {SoundId}", soundEffectId); } } + private Pair? ResolvePair(UserData userData) + { + var snapshot = _pairUiService.GetSnapshot(); + if (snapshot.PairsByUid.TryGetValue(userData.UID, out var pair)) + { + return pair; + } + + var ident = new PairUniqueIdentifier(userData.UID); + return _pairFactory.Create(ident); + } private void HandleNotificationMessage(NotificationMessage msg) { @@ -659,7 +681,14 @@ public class NotificationService : DisposableMediatorSubscriberBase, IHostedServ { try { - Mediator.Publish(new CyclePauseMessage(userData)); + var pair = ResolvePair(userData); + if (pair == null) + { + _logger.LogWarning("Cannot cycle pause {uid} because pair is missing", userData.UID); + throw new InvalidOperationException("Pair not available"); + } + + Mediator.Publish(new CyclePauseMessage(pair)); DismissNotification(notification); var displayName = GetUserDisplayName(userData, playerName); diff --git a/LightlessSync/Services/PairRequestService.cs b/LightlessSync/Services/PairRequestService.cs index 2531a3a..206fea3 100644 --- a/LightlessSync/Services/PairRequestService.cs +++ b/LightlessSync/Services/PairRequestService.cs @@ -1,6 +1,6 @@ using LightlessSync.LightlessConfiguration.Models; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; +using LightlessSync.UI.Services; using Microsoft.Extensions.Logging; namespace LightlessSync.Services; @@ -8,10 +8,11 @@ namespace LightlessSync.Services; public sealed class PairRequestService : DisposableMediatorSubscriberBase { private readonly DalamudUtilService _dalamudUtil; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly Lazy _apiController; private readonly Lock _syncRoot = new(); private readonly List _requests = []; + private readonly Dictionary _displayNameCache = new(StringComparer.Ordinal); private static readonly TimeSpan _expiration = TimeSpan.FromMinutes(5); @@ -19,12 +20,12 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase ILogger logger, LightlessMediator mediator, DalamudUtilService dalamudUtil, - PairManager pairManager, + PairUiService pairUiService, Lazy apiController) : base(logger, mediator) { _dalamudUtil = dalamudUtil; - _pairManager = pairManager; + _pairUiService = pairUiService; _apiController = apiController; Mediator.Subscribe(this, _ => @@ -96,6 +97,10 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase lock (_syncRoot) { removed = _requests.RemoveAll(r => string.Equals(r.HashedCid, hashedCid, StringComparison.Ordinal)) > 0; + if (removed) + { + _displayNameCache.Remove(hashedCid); + } } if (removed) @@ -129,6 +134,23 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase return string.Empty; } + if (TryGetCachedDisplayName(hashedCid, out var cached)) + { + return cached; + } + + var resolved = ResolveDisplayNameInternal(hashedCid); + if (!string.IsNullOrWhiteSpace(resolved)) + { + CacheDisplayName(hashedCid, resolved); + return resolved; + } + + return string.Empty; + } + + private string ResolveDisplayNameInternal(string hashedCid) + { var (name, address) = _dalamudUtil.FindPlayerByNameHash(hashedCid); if (!string.IsNullOrWhiteSpace(name)) { @@ -138,8 +160,9 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase : name; } - var pair = _pairManager - .GetOnlineUserPairs() + var snapshot = _pairUiService.GetSnapshot(); + var pair = snapshot.PairsByUid.Values + .Where(p => !string.IsNullOrEmpty(p.GetPlayerNameHash())) .FirstOrDefault(p => string.Equals(p.Ident, hashedCid, StringComparison.Ordinal)); if (pair != null) @@ -185,7 +208,21 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase } var now = DateTime.UtcNow; - return _requests.RemoveAll(r => now - r.ReceivedAt > _expiration) > 0; + var removedAny = false; + for (var i = _requests.Count - 1; i >= 0; i--) + { + var entry = _requests[i]; + if (now - entry.ReceivedAt <= _expiration) + { + continue; + } + + _displayNameCache.Remove(entry.HashedCid); + _requests.RemoveAt(i); + removedAny = true; + } + + return removedAny; } public void AcceptPairRequest(string hashedCid, string displayName) @@ -229,4 +266,32 @@ public sealed class PairRequestService : DisposableMediatorSubscriberBase private record struct PairRequestEntry(string HashedCid, string MessageTemplate, DateTime ReceivedAt); public readonly record struct PairRequestDisplay(string HashedCid, string DisplayName, string Message, DateTime ReceivedAt); + + private bool TryGetCachedDisplayName(string hashedCid, out string displayName) + { + lock (_syncRoot) + { + if (!string.IsNullOrWhiteSpace(hashedCid) && _displayNameCache.TryGetValue(hashedCid, out var cached)) + { + displayName = cached; + return true; + } + } + + displayName = string.Empty; + return false; + } + + private void CacheDisplayName(string hashedCid, string displayName) + { + if (string.IsNullOrWhiteSpace(hashedCid) || string.IsNullOrWhiteSpace(displayName) || string.Equals(hashedCid, displayName, StringComparison.Ordinal)) + { + return; + } + + lock (_syncRoot) + { + _displayNameCache[hashedCid] = displayName; + } + } } diff --git a/LightlessSync/Services/PlayerPerformanceService.cs b/LightlessSync/Services/PlayerPerformanceService.cs index 7db92e1..9382cf7 100644 --- a/LightlessSync/Services/PlayerPerformanceService.cs +++ b/LightlessSync/Services/PlayerPerformanceService.cs @@ -1,9 +1,13 @@ +using System; +using System.IO; using LightlessSync.API.Data; +using LightlessSync.API.Data.Extensions; using LightlessSync.FileCache; using LightlessSync.LightlessConfiguration; -using LightlessSync.PlayerData.Handlers; +using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Events; using LightlessSync.Services.Mediator; +using LightlessSync.Services.TextureCompression; using LightlessSync.UI; using LightlessSync.WebAPI.Files.Models; using Microsoft.Extensions.Logging; @@ -17,20 +21,22 @@ public class PlayerPerformanceService private readonly ILogger _logger; private readonly LightlessMediator _mediator; private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; + private readonly TextureDownscaleService _textureDownscaleService; private readonly Dictionary _warnedForPlayers = new(StringComparer.Ordinal); public PlayerPerformanceService(ILogger logger, LightlessMediator mediator, PlayerPerformanceConfigService playerPerformanceConfigService, FileCacheManager fileCacheManager, - XivDataAnalyzer xivDataAnalyzer) + XivDataAnalyzer xivDataAnalyzer, TextureDownscaleService textureDownscaleService) { _logger = logger; _mediator = mediator; _playerPerformanceConfigService = playerPerformanceConfigService; _fileCacheManager = fileCacheManager; _xivDataAnalyzer = xivDataAnalyzer; + _textureDownscaleService = textureDownscaleService; } - public async Task CheckBothThresholds(PairHandler pairHandler, CharacterData charaData) + public async Task CheckBothThresholds(IPairPerformanceSubject pairHandler, CharacterData charaData) { var config = _playerPerformanceConfigService.Current; bool notPausedAfterVram = ComputeAndAutoPauseOnVRAMUsageThresholds(pairHandler, charaData, []); @@ -39,37 +45,37 @@ public class PlayerPerformanceService if (!notPausedAfterTris) return false; if (config.UIDsToIgnore - .Exists(uid => string.Equals(uid, pairHandler.Pair.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pairHandler.Pair.UserData.UID, StringComparison.Ordinal))) + .Exists(uid => string.Equals(uid, pairHandler.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pairHandler.UserData.UID, StringComparison.Ordinal))) return true; - var vramUsage = pairHandler.Pair.LastAppliedApproximateVRAMBytes; - var triUsage = pairHandler.Pair.LastAppliedDataTris; + var vramUsage = pairHandler.LastAppliedApproximateVRAMBytes; + var triUsage = pairHandler.LastAppliedDataTris; - bool isPrefPerm = pairHandler.Pair.UserPair.OwnPermissions.HasFlag(API.Data.Enum.UserPermissions.Sticky); + bool isPrefPerm = pairHandler.HasStickyPermissions; - bool exceedsTris = CheckForThreshold(config.WarnOnExceedingThresholds, config.TrisWarningThresholdThousands * 1000, + bool exceedsTris = CheckForThreshold(config.WarnOnExceedingThresholds, config.TrisWarningThresholdThousands * 1000L, triUsage, config.WarnOnPreferredPermissionsExceedingThresholds, isPrefPerm); - bool exceedsVram = CheckForThreshold(config.WarnOnExceedingThresholds, config.VRAMSizeWarningThresholdMiB * 1024 * 1024, + bool exceedsVram = CheckForThreshold(config.WarnOnExceedingThresholds, config.VRAMSizeWarningThresholdMiB * 1024L * 1024L, vramUsage, config.WarnOnPreferredPermissionsExceedingThresholds, isPrefPerm); - if (_warnedForPlayers.TryGetValue(pairHandler.Pair.UserData.UID, out bool hadWarning) && hadWarning) + if (_warnedForPlayers.TryGetValue(pairHandler.UserData.UID, out bool hadWarning) && hadWarning) { - _warnedForPlayers[pairHandler.Pair.UserData.UID] = exceedsTris || exceedsVram; + _warnedForPlayers[pairHandler.UserData.UID] = exceedsTris || exceedsVram; return true; } - _warnedForPlayers[pairHandler.Pair.UserData.UID] = exceedsTris || exceedsVram; + _warnedForPlayers[pairHandler.UserData.UID] = exceedsTris || exceedsVram; if (exceedsVram) { - _mediator.Publish(new EventMessage(new Event(pairHandler.Pair.PlayerName, pairHandler.Pair.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, + _mediator.Publish(new EventMessage(new Event(pairHandler.PlayerName, pairHandler.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, $"Exceeds VRAM threshold: ({UiSharedService.ByteToString(vramUsage, addSuffix: true)}/{config.VRAMSizeWarningThresholdMiB} MiB)"))); } if (exceedsTris) { - _mediator.Publish(new EventMessage(new Event(pairHandler.Pair.PlayerName, pairHandler.Pair.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, + _mediator.Publish(new EventMessage(new Event(pairHandler.PlayerName, pairHandler.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, $"Exceeds triangle threshold: ({triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles)"))); } @@ -78,41 +84,40 @@ public class PlayerPerformanceService string warningText = string.Empty; if (exceedsTris && !exceedsVram) { - warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds your configured triangle warning threshold\n" + + warningText = $"Player {pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) exceeds your configured triangle warning threshold\n" + $"{triUsage}/{config.TrisWarningThresholdThousands * 1000} triangles"; } else if (!exceedsTris) { - warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds your configured VRAM warning threshold\n" + + warningText = $"Player {pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) exceeds your configured VRAM warning threshold\n" + $"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB} MiB"; } else { - warningText = $"Player {pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds both VRAM warning threshold and triangle warning threshold\n" + + warningText = $"Player {pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) exceeds both VRAM warning threshold and triangle warning threshold\n" + $"{UiSharedService.ByteToString(vramUsage, true)}/{config.VRAMSizeWarningThresholdMiB} MiB and {triUsage}/{config.TrisWarningThresholdThousands * 1000} triangles"; } _mediator.Publish(new PerformanceNotificationMessage( - $"{pairHandler.Pair.PlayerName} ({pairHandler.Pair.UserData.AliasOrUID}) exceeds performance threshold(s)", + $"{pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) exceeds performance threshold(s)", warningText, - pairHandler.Pair.UserData, - pairHandler.Pair.IsPaused, - pairHandler.Pair.PlayerName)); + pairHandler.UserData, + pairHandler.IsPaused, + pairHandler.PlayerName)); } return true; } - public async Task CheckTriangleUsageThresholds(PairHandler pairHandler, CharacterData charaData) + public async Task CheckTriangleUsageThresholds(IPairPerformanceSubject pairHandler, CharacterData charaData) { var config = _playerPerformanceConfigService.Current; - var pair = pairHandler.Pair; long triUsage = 0; if (!charaData.FileReplacements.TryGetValue(API.Data.Enum.ObjectKind.Player, out List? playerReplacements)) { - pair.LastAppliedDataTris = 0; + pairHandler.LastAppliedDataTris = 0; return true; } @@ -126,35 +131,35 @@ public class PlayerPerformanceService triUsage += await _xivDataAnalyzer.GetTrianglesByHash(hash).ConfigureAwait(false); } - pair.LastAppliedDataTris = triUsage; + pairHandler.LastAppliedDataTris = triUsage; _logger.LogDebug("Calculated VRAM usage for {p}", pairHandler); // no warning of any kind on ignored pairs if (config.UIDsToIgnore - .Exists(uid => string.Equals(uid, pair.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pair.UserData.UID, StringComparison.Ordinal))) + .Exists(uid => string.Equals(uid, pairHandler.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pairHandler.UserData.UID, StringComparison.Ordinal))) return true; - bool isPrefPerm = pair.UserPair.OwnPermissions.HasFlag(API.Data.Enum.UserPermissions.Sticky); + bool isPrefPerm = pairHandler.HasStickyPermissions; // now check auto pause - if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.TrisAutoPauseThresholdThousands * 1000, + if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.TrisAutoPauseThresholdThousands * 1000L, triUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm)) { - var message = $"Player {pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeded your configured triangle auto pause threshold and has been automatically paused\n" + + var message = $"Player {pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) exceeded your configured triangle auto pause threshold and has been automatically paused\n" + $"{triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles"; _mediator.Publish(new PerformanceNotificationMessage( - $"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused", + $"{pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) automatically paused", message, - pair.UserData, + pairHandler.UserData, true, - pair.PlayerName)); + pairHandler.PlayerName)); - _mediator.Publish(new EventMessage(new Event(pair.PlayerName, pair.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, + _mediator.Publish(new EventMessage(new Event(pairHandler.PlayerName, pairHandler.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, $"Exceeds triangle threshold: automatically paused ({triUsage}/{config.TrisAutoPauseThresholdThousands * 1000} triangles)"))); - _mediator.Publish(new PauseMessage(pair.UserData)); + _mediator.Publish(new PauseMessage(pairHandler.UserData)); return false; } @@ -162,16 +167,18 @@ public class PlayerPerformanceService return true; } - public bool ComputeAndAutoPauseOnVRAMUsageThresholds(PairHandler pairHandler, CharacterData charaData, List toDownloadFiles) + public bool ComputeAndAutoPauseOnVRAMUsageThresholds(IPairPerformanceSubject pairHandler, CharacterData charaData, List toDownloadFiles) { var config = _playerPerformanceConfigService.Current; - var pair = pairHandler.Pair; + bool skipDownscale = pairHandler.IsDirectlyPaired && pairHandler.HasStickyPermissions; long vramUsage = 0; + long effectiveVramUsage = 0; if (!charaData.FileReplacements.TryGetValue(API.Data.Enum.ObjectKind.Player, out List? playerReplacements)) { - pair.LastAppliedApproximateVRAMBytes = 0; + pairHandler.LastAppliedApproximateVRAMBytes = 0; + pairHandler.LastAppliedApproximateEffectiveVRAMBytes = 0; return true; } @@ -183,11 +190,13 @@ public class PlayerPerformanceService foreach (var hash in moddedTextureHashes) { long fileSize = 0; + long effectiveSize = 0; var download = toDownloadFiles.Find(f => string.Equals(hash, f.Hash, StringComparison.OrdinalIgnoreCase)); if (download != null) { fileSize = download.TotalRaw; + effectiveSize = fileSize; } else { @@ -201,39 +210,63 @@ public class PlayerPerformanceService } fileSize = fileEntry.Size.Value; + effectiveSize = fileSize; + + if (!skipDownscale) + { + var preferredPath = _textureDownscaleService.GetPreferredPath(hash, fileEntry.ResolvedFilepath); + if (!string.IsNullOrEmpty(preferredPath) && File.Exists(preferredPath)) + { + try + { + effectiveSize = new FileInfo(preferredPath).Length; + } + catch (Exception ex) + { + _logger.LogTrace(ex, "Failed to read size for preferred texture path {Path}", preferredPath); + effectiveSize = fileSize; + } + } + else + { + effectiveSize = fileSize; + } + } } vramUsage += fileSize; + effectiveVramUsage += effectiveSize; } - pair.LastAppliedApproximateVRAMBytes = vramUsage; + pairHandler.LastAppliedApproximateVRAMBytes = vramUsage; + pairHandler.LastAppliedApproximateEffectiveVRAMBytes = effectiveVramUsage; _logger.LogDebug("Calculated VRAM usage for {p}", pairHandler); // no warning of any kind on ignored pairs if (config.UIDsToIgnore - .Exists(uid => string.Equals(uid, pair.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pair.UserData.UID, StringComparison.Ordinal))) + .Exists(uid => string.Equals(uid, pairHandler.UserData.Alias, StringComparison.Ordinal) || string.Equals(uid, pairHandler.UserData.UID, StringComparison.Ordinal))) return true; - bool isPrefPerm = pair.UserPair.OwnPermissions.HasFlag(API.Data.Enum.UserPermissions.Sticky); + bool isPrefPerm = pairHandler.HasStickyPermissions; // now check auto pause - if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.VRAMSizeAutoPauseThresholdMiB * 1024 * 1024, + if (CheckForThreshold(config.AutoPausePlayersExceedingThresholds, config.VRAMSizeAutoPauseThresholdMiB * 1024L * 1024L, vramUsage, config.AutoPausePlayersWithPreferredPermissionsExceedingThresholds, isPrefPerm)) { - var message = $"Player {pair.PlayerName} ({pair.UserData.AliasOrUID}) exceeded your configured VRAM auto pause threshold and has been automatically paused\n" + + var message = $"Player {pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) exceeded your configured VRAM auto pause threshold and has been automatically paused\n" + $"{UiSharedService.ByteToString(vramUsage, addSuffix: true)}/{config.VRAMSizeAutoPauseThresholdMiB}MiB"; - + _mediator.Publish(new PerformanceNotificationMessage( - $"{pair.PlayerName} ({pair.UserData.AliasOrUID}) automatically paused", + $"{pairHandler.PlayerName} ({pairHandler.UserData.AliasOrUID}) automatically paused", message, - pair.UserData, + pairHandler.UserData, true, - pair.PlayerName)); + pairHandler.PlayerName)); - _mediator.Publish(new PauseMessage(pair.UserData)); + _mediator.Publish(new PauseMessage(pairHandler.UserData)); - _mediator.Publish(new EventMessage(new Event(pair.PlayerName, pair.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, + _mediator.Publish(new EventMessage(new Event(pairHandler.PlayerName, pairHandler.UserData, nameof(PlayerPerformanceService), EventSeverity.Warning, $"Exceeds VRAM threshold: automatically paused ({UiSharedService.ByteToString(vramUsage, addSuffix: true)}/{config.VRAMSizeAutoPauseThresholdMiB} MiB)"))); return false; diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index 388ac87..5cb3e15 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -252,9 +252,16 @@ public class ServerConfigurationManager public void SelectServer(int idx) { + var previousIndex = _configService.Current.CurrentServer; _configService.Current.CurrentServer = idx; CurrentServer!.FullPause = false; Save(); + + if (previousIndex != idx) + { + var serverUrl = CurrentServer.ServerUri; + _lightlessMediator.Publish(new ActiveServerChangedMessage(serverUrl)); + } } internal void AddCurrentCharacterToServer(int serverSelectionIndex = -1) diff --git a/LightlessSync/Services/TextureCompression/TexFileHelper.cs b/LightlessSync/Services/TextureCompression/TexFileHelper.cs new file mode 100644 index 0000000..b5e2ab8 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TexFileHelper.cs @@ -0,0 +1,282 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using Lumina.Data.Files; +using OtterTex; + +namespace LightlessSync.Services.TextureCompression; + +// base taken from penumbra mostly +internal static class TexFileHelper +{ + private const int HeaderSize = 80; + private const int MaxMipLevels = 13; + + public static ScratchImage Load(string path) + { + using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); + return Load(stream); + } + + public static ScratchImage Load(Stream stream) + { + using var reader = new BinaryReader(stream, System.Text.Encoding.UTF8, leaveOpen: true); + var header = ReadHeader(reader); + var meta = CreateMeta(header); + meta.MipLevels = ComputeMipCount(stream.Length, header, meta); + if (meta.MipLevels == 0) + { + throw new InvalidOperationException("TEX file does not contain a valid mip chain."); + } + + var scratch = ScratchImage.Initialize(meta); + ReadPixelData(reader, scratch); + return scratch; + } + + public static void Save(string path, ScratchImage image) + { + var header = BuildHeader(image); + if (header.Format == TexFile.TextureFormat.Unknown) + { + throw new InvalidOperationException($"Unable to export TEX file with unsupported format {image.Meta.Format}."); + } + + var mode = File.Exists(path) ? FileMode.Truncate : FileMode.CreateNew; + using var stream = new FileStream(path, mode, FileAccess.Write, FileShare.Read); + using var writer = new BinaryWriter(stream); + WriteHeader(writer, header); + writer.Write(image.Pixels); + GC.KeepAlive(image); + } + + private static TexFile.TexHeader ReadHeader(BinaryReader reader) + { + Span buffer = stackalloc byte[HeaderSize]; + var read = reader.Read(buffer); + if (read != HeaderSize) + { + throw new EndOfStreamException($"Incomplete TEX header: expected {HeaderSize} bytes, read {read} bytes."); + } + + return MemoryMarshal.Read(buffer); + } + + private static TexMeta CreateMeta(in TexFile.TexHeader header) + { + var meta = new TexMeta + { + Width = header.Width, + Height = header.Height, + Depth = Math.Max(header.Depth, (ushort)1), + ArraySize = 1, + MipLevels = header.MipCount, + Format = header.Format.ToDxgi(), + Dimension = header.Type.ToDimension(), + MiscFlags = header.Type.HasFlag(TexFile.Attribute.TextureTypeCube) ? D3DResourceMiscFlags.TextureCube : 0, + MiscFlags2 = 0, + }; + + if (meta.Format == DXGIFormat.Unknown) + { + throw new InvalidOperationException($"TEX format {header.Format} cannot be mapped to DXGI."); + } + + if (meta.Dimension == TexDimension.Unknown) + { + throw new InvalidOperationException($"Unrecognised TEX dimension attribute {header.Type}."); + } + + return meta; + } + + private static unsafe int ComputeMipCount(long totalLength, in TexFile.TexHeader header, in TexMeta meta) + { + var width = Math.Max(meta.Width, 1); + var height = Math.Max(meta.Height, 1); + var minSide = meta.Format.IsCompressed() ? 4 : 1; + var bitsPerPixel = meta.Format.BitsPerPixel(); + + var expectedOffset = HeaderSize; + var remaining = totalLength - HeaderSize; + + for (var level = 0; level < MaxMipLevels; level++) + { + var declaredOffset = header.OffsetToSurface[level]; + if (declaredOffset == 0) + { + return level; + } + + if (declaredOffset != expectedOffset || remaining <= 0) + { + return level; + } + + var mipSize = (int)((long)width * height * bitsPerPixel / 8); + if (mipSize > remaining) + { + return level; + } + + expectedOffset += mipSize; + remaining -= mipSize; + + if (width <= minSide && height <= minSide) + { + return level + 1; + } + + width = Math.Max(width / 2, minSide); + height = Math.Max(height / 2, minSide); + } + + return MaxMipLevels; + } + + private static unsafe void ReadPixelData(BinaryReader reader, ScratchImage image) + { + fixed (byte* destination = image.Pixels) + { + var span = new Span(destination, image.Pixels.Length); + var read = reader.Read(span); + if (read < span.Length) + { + throw new InvalidDataException($"TEX pixel buffer is truncated (read {read} of {span.Length} bytes)."); + } + } + } + + private static TexFile.TexHeader BuildHeader(ScratchImage image) + { + var meta = image.Meta; + var header = new TexFile.TexHeader + { + Width = (ushort)meta.Width, + Height = (ushort)meta.Height, + Depth = (ushort)Math.Max(meta.Depth, 1), + MipCount = (byte)Math.Min(meta.MipLevels, MaxMipLevels), + Format = meta.Format.ToTex(), + Type = meta.Dimension switch + { + _ when meta.IsCubeMap => TexFile.Attribute.TextureTypeCube, + TexDimension.Tex1D => TexFile.Attribute.TextureType1D, + TexDimension.Tex2D => TexFile.Attribute.TextureType2D, + TexDimension.Tex3D => TexFile.Attribute.TextureType3D, + _ => 0, + }, + }; + + PopulateOffsets(ref header, image); + return header; + } + + private static unsafe void PopulateOffsets(ref TexFile.TexHeader header, ScratchImage image) + { + var index = 0; + fixed (byte* basePtr = image.Pixels) + { + foreach (var mip in image.Images) + { + if (index >= MaxMipLevels) + { + break; + } + + var byteOffset = (byte*)mip.Pixels - basePtr; + header.OffsetToSurface[index++] = HeaderSize + (uint)byteOffset; + } + } + + while (index < MaxMipLevels) + { + header.OffsetToSurface[index++] = 0; + } + + header.LodOffset[0] = 0; + header.LodOffset[1] = (byte)Math.Min(header.MipCount - 1, 1); + header.LodOffset[2] = (byte)Math.Min(header.MipCount - 1, 2); + } + + private static unsafe void WriteHeader(BinaryWriter writer, in TexFile.TexHeader header) + { + writer.Write((uint)header.Type); + writer.Write((uint)header.Format); + writer.Write(header.Width); + writer.Write(header.Height); + writer.Write(header.Depth); + writer.Write((byte)(header.MipCount | (header.MipUnknownFlag ? 0x80 : 0))); + writer.Write(header.ArraySize); + writer.Write(header.LodOffset[0]); + writer.Write(header.LodOffset[1]); + writer.Write(header.LodOffset[2]); + for (var i = 0; i < MaxMipLevels; i++) + { + writer.Write(header.OffsetToSurface[i]); + } + } + + private static TexDimension ToDimension(this TexFile.Attribute attribute) + => (attribute & TexFile.Attribute.TextureTypeMask) switch + { + TexFile.Attribute.TextureType1D => TexDimension.Tex1D, + TexFile.Attribute.TextureType2D => TexDimension.Tex2D, + TexFile.Attribute.TextureType3D => TexDimension.Tex3D, + _ => TexDimension.Unknown, + }; + + private static DXGIFormat ToDxgi(this TexFile.TextureFormat format) + => format switch + { + TexFile.TextureFormat.L8 => DXGIFormat.R8UNorm, + TexFile.TextureFormat.A8 => DXGIFormat.A8UNorm, + TexFile.TextureFormat.B4G4R4A4 => DXGIFormat.B4G4R4A4UNorm, + TexFile.TextureFormat.B5G5R5A1 => DXGIFormat.B5G5R5A1UNorm, + TexFile.TextureFormat.B8G8R8A8 => DXGIFormat.B8G8R8A8UNorm, + TexFile.TextureFormat.B8G8R8X8 => DXGIFormat.B8G8R8X8UNorm, + TexFile.TextureFormat.R32F => DXGIFormat.R32Float, + TexFile.TextureFormat.R16G16F => DXGIFormat.R16G16Float, + TexFile.TextureFormat.R32G32F => DXGIFormat.R32G32Float, + TexFile.TextureFormat.R16G16B16A16F => DXGIFormat.R16G16B16A16Float, + TexFile.TextureFormat.R32G32B32A32F => DXGIFormat.R32G32B32A32Float, + TexFile.TextureFormat.BC1 => DXGIFormat.BC1UNorm, + TexFile.TextureFormat.BC2 => DXGIFormat.BC2UNorm, + TexFile.TextureFormat.BC3 => DXGIFormat.BC3UNorm, + (TexFile.TextureFormat)0x6120 => DXGIFormat.BC4UNorm, + TexFile.TextureFormat.BC5 => DXGIFormat.BC5UNorm, + (TexFile.TextureFormat)0x6330 => DXGIFormat.BC6HSF16, + TexFile.TextureFormat.BC7 => DXGIFormat.BC7UNorm, + TexFile.TextureFormat.D16 => DXGIFormat.R16G16B16A16Typeless, + TexFile.TextureFormat.D24S8 => DXGIFormat.R24G8Typeless, + TexFile.TextureFormat.Shadow16 => DXGIFormat.R16Typeless, + TexFile.TextureFormat.Shadow24 => DXGIFormat.R24G8Typeless, + _ => DXGIFormat.Unknown, + }; + + private static TexFile.TextureFormat ToTex(this DXGIFormat format) + => format switch + { + DXGIFormat.R8UNorm => TexFile.TextureFormat.L8, + DXGIFormat.A8UNorm => TexFile.TextureFormat.A8, + DXGIFormat.B4G4R4A4UNorm => TexFile.TextureFormat.B4G4R4A4, + DXGIFormat.B5G5R5A1UNorm => TexFile.TextureFormat.B5G5R5A1, + DXGIFormat.B8G8R8A8UNorm => TexFile.TextureFormat.B8G8R8A8, + DXGIFormat.B8G8R8X8UNorm => TexFile.TextureFormat.B8G8R8X8, + DXGIFormat.R32Float => TexFile.TextureFormat.R32F, + DXGIFormat.R16G16Float => TexFile.TextureFormat.R16G16F, + DXGIFormat.R32G32Float => TexFile.TextureFormat.R32G32F, + DXGIFormat.R16G16B16A16Float => TexFile.TextureFormat.R16G16B16A16F, + DXGIFormat.R32G32B32A32Float => TexFile.TextureFormat.R32G32B32A32F, + DXGIFormat.BC1UNorm => TexFile.TextureFormat.BC1, + DXGIFormat.BC2UNorm => TexFile.TextureFormat.BC2, + DXGIFormat.BC3UNorm => TexFile.TextureFormat.BC3, + DXGIFormat.BC4UNorm => (TexFile.TextureFormat)0x6120, + DXGIFormat.BC5UNorm => TexFile.TextureFormat.BC5, + DXGIFormat.BC6HSF16 => (TexFile.TextureFormat)0x6330, + DXGIFormat.BC7UNorm => TexFile.TextureFormat.BC7, + DXGIFormat.R16G16B16A16Typeless => TexFile.TextureFormat.D16, + DXGIFormat.R24G8Typeless => TexFile.TextureFormat.D24S8, + DXGIFormat.R16Typeless => TexFile.TextureFormat.Shadow16, + _ => TexFile.TextureFormat.Unknown, + }; +} diff --git a/LightlessSync/Services/TextureCompression/TextureCompressionCapabilities.cs b/LightlessSync/Services/TextureCompression/TextureCompressionCapabilities.cs new file mode 100644 index 0000000..81e10c5 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureCompressionCapabilities.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using Penumbra.Api.Enums; + +namespace LightlessSync.Services.TextureCompression; + +internal static class TextureCompressionCapabilities +{ + private static readonly ImmutableDictionary TexTargets = + new Dictionary + { + [TextureCompressionTarget.BC7] = TextureType.Bc7Tex, + [TextureCompressionTarget.BC3] = TextureType.Bc3Tex, + }.ToImmutableDictionary(); + + private static readonly ImmutableDictionary DdsTargets = + new Dictionary + { + [TextureCompressionTarget.BC7] = TextureType.Bc7Dds, + [TextureCompressionTarget.BC3] = TextureType.Bc3Dds, + }.ToImmutableDictionary(); + + private static readonly TextureCompressionTarget[] SelectableTargetsCache = TexTargets + .Select(kvp => kvp.Key) + .OrderBy(t => t) + .ToArray(); + + private static readonly HashSet SelectableTargetSet = SelectableTargetsCache.ToHashSet(); + + public static IReadOnlyList SelectableTargets => SelectableTargetsCache; + + public static TextureCompressionTarget DefaultTarget => TextureCompressionTarget.BC7; + + public static bool IsSelectable(TextureCompressionTarget target) => SelectableTargetSet.Contains(target); + + public static TextureCompressionTarget Normalize(TextureCompressionTarget? desired) + { + if (desired.HasValue && IsSelectable(desired.Value)) + { + return desired.Value; + } + + return DefaultTarget; + } + + public static bool TryGetPenumbraTarget(TextureCompressionTarget target, string? outputPath, out TextureType textureType) + { + if (!string.IsNullOrWhiteSpace(outputPath) && + string.Equals(Path.GetExtension(outputPath), ".dds", StringComparison.OrdinalIgnoreCase)) + { + return DdsTargets.TryGetValue(target, out textureType); + } + + return TexTargets.TryGetValue(target, out textureType); + } +} diff --git a/LightlessSync/Services/TextureCompression/TextureCompressionRequest.cs b/LightlessSync/Services/TextureCompression/TextureCompressionRequest.cs new file mode 100644 index 0000000..0877d55 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureCompressionRequest.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace LightlessSync.Services.TextureCompression; + +public sealed record TextureCompressionRequest( + string PrimaryFilePath, + IReadOnlyList DuplicateFilePaths, + TextureCompressionTarget Target); diff --git a/LightlessSync/Services/TextureCompression/TextureCompressionService.cs b/LightlessSync/Services/TextureCompression/TextureCompressionService.cs new file mode 100644 index 0000000..2d4a1d2 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureCompressionService.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using LightlessSync.Interop.Ipc; +using LightlessSync.FileCache; +using Microsoft.Extensions.Logging; +using Penumbra.Api.Enums; + +namespace LightlessSync.Services.TextureCompression; + +public sealed class TextureCompressionService +{ + private readonly ILogger _logger; + private readonly IpcManager _ipcManager; + private readonly FileCacheManager _fileCacheManager; + + public IReadOnlyList SelectableTargets => TextureCompressionCapabilities.SelectableTargets; + public TextureCompressionTarget DefaultTarget => TextureCompressionCapabilities.DefaultTarget; + + public TextureCompressionService( + ILogger logger, + IpcManager ipcManager, + FileCacheManager fileCacheManager) + { + _logger = logger; + _ipcManager = ipcManager; + _fileCacheManager = fileCacheManager; + } + + public async Task ConvertTexturesAsync( + IReadOnlyList requests, + IProgress? progress, + CancellationToken token) + { + if (requests.Count == 0) + { + return; + } + + var total = requests.Count; + var completed = 0; + + foreach (var request in requests) + { + token.ThrowIfCancellationRequested(); + + if (!TextureCompressionCapabilities.TryGetPenumbraTarget(request.Target, request.PrimaryFilePath, out var textureType)) + { + _logger.LogWarning("Unsupported compression target {Target} requested.", request.Target); + completed++; + continue; + } + + await RunPenumbraConversionAsync(request, textureType, total, completed, progress, token).ConfigureAwait(false); + + completed++; + } + } + + public bool IsTargetSelectable(TextureCompressionTarget target) => TextureCompressionCapabilities.IsSelectable(target); + + public TextureCompressionTarget NormalizeTarget(TextureCompressionTarget? desired) => + TextureCompressionCapabilities.Normalize(desired); + + private async Task RunPenumbraConversionAsync( + TextureCompressionRequest request, + TextureType targetType, + int total, + int completedBefore, + IProgress? progress, + CancellationToken token) + { + var primaryPath = request.PrimaryFilePath; + var displayJob = new TextureConversionJob( + primaryPath, + primaryPath, + targetType, + IncludeMipMaps: true, + request.DuplicateFilePaths); + + var backupPath = CreateBackupCopy(primaryPath); + var conversionJob = displayJob with { InputFile = backupPath }; + + progress?.Report(new TextureConversionProgress(completedBefore, total, displayJob)); + + try + { + WaitForAccess(primaryPath); + await _ipcManager.Penumbra.ConvertTextureFiles(_logger, new[] { conversionJob }, null, token).ConfigureAwait(false); + + if (!IsValidConversionResult(displayJob.OutputFile)) + { + throw new InvalidOperationException($"Penumbra conversion produced no output for {displayJob.OutputFile}."); + } + + UpdateFileCache(displayJob); + + progress?.Report(new TextureConversionProgress(completedBefore + 1, total, displayJob)); + } + catch (Exception ex) + { + RestoreFromBackup(backupPath, displayJob.OutputFile, displayJob.DuplicateTargets, ex); + throw; + } + finally + { + CleanupBackup(backupPath); + } + } + + private void UpdateFileCache(TextureConversionJob job) + { + var paths = new HashSet(StringComparer.OrdinalIgnoreCase) + { + job.OutputFile + }; + + if (job.DuplicateTargets is { Count: > 0 }) + { + foreach (var duplicate in job.DuplicateTargets) + { + paths.Add(duplicate); + } + } + + if (paths.Count == 0) + { + return; + } + + var cacheEntries = _fileCacheManager.GetFileCachesByPaths(paths.ToArray()); + foreach (var path in paths) + { + if (!cacheEntries.TryGetValue(path, out var entry) || entry is null) + { + entry = _fileCacheManager.CreateFileEntry(path); + if (entry is null) + { + _logger.LogWarning("Unable to locate cache entry for {Path}; skipping hash refresh", path); + continue; + } + } + + try + { + _fileCacheManager.UpdateHashedFile(entry); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to refresh file cache entry for {Path}", path); + } + } + } + + private static readonly string WorkingDirectory = + Path.Combine(Path.GetTempPath(), "LightlessSync.TextureCompression"); + + private static string CreateBackupCopy(string filePath) + { + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"Cannot back up missing texture file {filePath}.", filePath); + } + + Directory.CreateDirectory(WorkingDirectory); + + var extension = Path.GetExtension(filePath); + if (string.IsNullOrEmpty(extension)) + { + extension = ".tmp"; + } + + var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); + var backupName = $"{fileNameWithoutExtension}.backup.{Guid.NewGuid():N}{extension}"; + var backupPath = Path.Combine(WorkingDirectory, backupName); + + WaitForAccess(filePath); + + File.Copy(filePath, backupPath, overwrite: false); + + return backupPath; + } + + private const int MaxAccessRetries = 10; + private static readonly TimeSpan AccessRetryDelay = TimeSpan.FromMilliseconds(200); + + private static void WaitForAccess(string filePath) + { + if (!File.Exists(filePath)) + { + return; + } + + try + { + File.SetAttributes(filePath, FileAttributes.Normal); + } + catch + { + // ignore attribute changes here + } + + Exception? lastException = null; + for (var attempt = 0; attempt < MaxAccessRetries; attempt++) + { + try + { + using var stream = new FileStream( + filePath, + FileMode.Open, + FileAccess.Read, + FileShare.None); + return; + } + catch (IOException ex) when (IsSharingViolation(ex)) + { + lastException = ex; + } + + Thread.Sleep(AccessRetryDelay); + } + + if (lastException != null) + { + throw lastException; + } + } + + private static bool IsSharingViolation(IOException ex) => + ex.HResult == unchecked((int)0x80070020); + + private void RestoreFromBackup( + string backupPath, + string destinationPath, + IReadOnlyList? duplicateTargets, + Exception reason) + { + if (string.IsNullOrEmpty(backupPath)) + { + _logger.LogWarning(reason, "Conversion failed for {File}, but no backup was available to restore.", destinationPath); + return; + } + + if (!File.Exists(backupPath)) + { + _logger.LogWarning(reason, "Conversion failed for {File}, but backup path {Backup} no longer exists.", destinationPath, backupPath); + return; + } + + try + { + TryReplaceFile(backupPath, destinationPath); + } + catch (Exception restoreEx) + { + _logger.LogError(restoreEx, "Failed to restore texture {File} after conversion failure.", destinationPath); + return; + } + + if (duplicateTargets is { Count: > 0 }) + { + foreach (var duplicate in duplicateTargets) + { + if (string.Equals(destinationPath, duplicate, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + try + { + File.Copy(destinationPath, duplicate, overwrite: true); + } + catch (Exception duplicateEx) + { + _logger.LogDebug(duplicateEx, "Failed to restore duplicate {Duplicate} after conversion failure.", duplicate); + } + } + } + + _logger.LogWarning(reason, "Restored original texture {File} after conversion failure.", destinationPath); + } + + private static void TryReplaceFile(string sourcePath, string destinationPath) + { + WaitForAccess(destinationPath); + + var destinationDirectory = Path.GetDirectoryName(destinationPath); + if (!string.IsNullOrEmpty(destinationDirectory)) + { + Directory.CreateDirectory(destinationDirectory); + } + + File.Copy(sourcePath, destinationPath, overwrite: true); + } + + private static void CleanupBackup(string backupPath) + { + if (string.IsNullOrEmpty(backupPath)) + { + return; + } + + try + { + if (File.Exists(backupPath)) + { + File.Delete(backupPath); + } + } + catch + { + // avoid killing successful conversions on cleanup failure + } + } + + private static bool IsValidConversionResult(string path) + { + try + { + var fileInfo = new FileInfo(path); + return fileInfo.Exists && fileInfo.Length > 0; + } + catch + { + return false; + } + } +} diff --git a/LightlessSync/Services/TextureCompression/TextureCompressionTarget.cs b/LightlessSync/Services/TextureCompression/TextureCompressionTarget.cs new file mode 100644 index 0000000..0928da4 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureCompressionTarget.cs @@ -0,0 +1,10 @@ +namespace LightlessSync.Services.TextureCompression; + +public enum TextureCompressionTarget +{ + BC1, + BC3, + BC4, + BC5, + BC7 +} diff --git a/LightlessSync/Services/TextureCompression/TextureDownscaleService.cs b/LightlessSync/Services/TextureCompression/TextureDownscaleService.cs new file mode 100644 index 0000000..e5ead9d --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureDownscaleService.cs @@ -0,0 +1,955 @@ +using System; +using System.Collections.Concurrent; +using System.Buffers.Binary; +using System.Globalization; +using System.Numerics; +using System.IO; +using OtterTex; +using OtterImage = OtterTex.Image; +using LightlessSync.LightlessConfiguration; +using LightlessSync.FileCache; +using Microsoft.Extensions.Logging; +using Lumina.Data.Files; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +/* + * Index upscaler code (converted/reversed for downscaling purposes) provided by Ny + * OtterTex made by Ottermandias + * thank you!! +*/ + +namespace LightlessSync.Services.TextureCompression; + +public sealed class TextureDownscaleService +{ + private const int DefaultTargetMaxDimension = 2048; + private const int MaxSupportedTargetDimension = 8192; + private const int BlockMultiple = 4; + + private readonly ILogger _logger; + private readonly LightlessConfigService _configService; + private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; + private readonly FileCacheManager _fileCacheManager; + + private readonly ConcurrentDictionary _activeJobs = new(StringComparer.OrdinalIgnoreCase); + private readonly ConcurrentDictionary _downscaledPaths = new(StringComparer.OrdinalIgnoreCase); + private static readonly IReadOnlyDictionary BlockCompressedFormatMap = + new Dictionary + { + [70] = TextureCompressionTarget.BC1, // DXGI_FORMAT_BC1_TYPELESS + [71] = TextureCompressionTarget.BC1, // DXGI_FORMAT_BC1_UNORM + [72] = TextureCompressionTarget.BC1, // DXGI_FORMAT_BC1_UNORM_SRGB + + [73] = TextureCompressionTarget.BC3, // DXGI_FORMAT_BC2_TYPELESS + [74] = TextureCompressionTarget.BC3, // DXGI_FORMAT_BC2_UNORM + [75] = TextureCompressionTarget.BC3, // DXGI_FORMAT_BC2_UNORM_SRGB + [76] = TextureCompressionTarget.BC3, // DXGI_FORMAT_BC3_TYPELESS + [77] = TextureCompressionTarget.BC3, // DXGI_FORMAT_BC3_UNORM + [78] = TextureCompressionTarget.BC3, // DXGI_FORMAT_BC3_UNORM_SRGB + + [79] = TextureCompressionTarget.BC4, // DXGI_FORMAT_BC4_TYPELESS + [80] = TextureCompressionTarget.BC4, // DXGI_FORMAT_BC4_UNORM + [81] = TextureCompressionTarget.BC4, // DXGI_FORMAT_BC4_SNORM + + [82] = TextureCompressionTarget.BC5, // DXGI_FORMAT_BC5_TYPELESS + [83] = TextureCompressionTarget.BC5, // DXGI_FORMAT_BC5_UNORM + [84] = TextureCompressionTarget.BC5, // DXGI_FORMAT_BC5_SNORM + + [94] = TextureCompressionTarget.BC7, // DXGI_FORMAT_BC6H_TYPELESS (treated as BC7 for block detection) + [95] = TextureCompressionTarget.BC7, // DXGI_FORMAT_BC6H_UF16 + [96] = TextureCompressionTarget.BC7, // DXGI_FORMAT_BC6H_SF16 + [97] = TextureCompressionTarget.BC7, // DXGI_FORMAT_BC7_TYPELESS + [98] = TextureCompressionTarget.BC7, // DXGI_FORMAT_BC7_UNORM + [99] = TextureCompressionTarget.BC7, // DXGI_FORMAT_BC7_UNORM_SRGB + }; + + public TextureDownscaleService( + ILogger logger, + LightlessConfigService configService, + PlayerPerformanceConfigService playerPerformanceConfigService, + FileCacheManager fileCacheManager) + { + _logger = logger; + _configService = configService; + _playerPerformanceConfigService = playerPerformanceConfigService; + _fileCacheManager = fileCacheManager; + } + + public void ScheduleDownscale(string hash, string filePath, TextureMapKind mapKind) + { + if (!filePath.EndsWith(".tex", StringComparison.OrdinalIgnoreCase)) return; + if (_activeJobs.ContainsKey(hash)) return; + + _activeJobs[hash] = Task.Run(() => DownscaleInternalAsync(hash, filePath, mapKind), CancellationToken.None); + } + + public string GetPreferredPath(string hash, string originalPath) + { + if (_downscaledPaths.TryGetValue(hash, out var existing) && File.Exists(existing)) + { + return existing; + } + + var resolved = GetExistingDownscaledPath(hash); + if (!string.IsNullOrEmpty(resolved)) + { + _downscaledPaths[hash] = resolved; + return resolved; + } + + return originalPath; + } + + private async Task DownscaleInternalAsync(string hash, string sourcePath, TextureMapKind mapKind) + { + TexHeaderInfo? headerInfo = null; + string? destination = null; + int targetMaxDimension = 0; + bool onlyDownscaleUncompressed = false; + bool? isIndexTexture = null; + + try + { + if (!File.Exists(sourcePath)) + { + _logger.LogWarning("Cannot downscale texture {Hash}; source path missing: {Path}", hash, sourcePath); + return; + } + + headerInfo = TryReadTexHeader(sourcePath, out var header) + ? header + : (TexHeaderInfo?)null; + var performanceConfig = _playerPerformanceConfigService.Current; + targetMaxDimension = ResolveTargetMaxDimension(); + onlyDownscaleUncompressed = performanceConfig.OnlyDownscaleUncompressedTextures; + + destination = Path.Combine(GetDownscaledDirectory(), $"{hash}.tex"); + if (File.Exists(destination)) + { + RegisterDownscaledTexture(hash, sourcePath, destination); + return; + } + + var indexTexture = IsIndexMap(mapKind); + isIndexTexture = indexTexture; + if (!indexTexture) + { + if (performanceConfig.EnableNonIndexTextureMipTrim + && await TryDropTopMipAsync(hash, sourcePath, destination, targetMaxDimension, onlyDownscaleUncompressed, headerInfo).ConfigureAwait(false)) + { + return; + } + + if (!performanceConfig.EnableNonIndexTextureMipTrim) + { + _logger.LogTrace("Skipping mip trim for non-index texture {Hash}; feature disabled.", hash); + } + + _downscaledPaths[hash] = sourcePath; + _logger.LogTrace("Skipping downscale for non-index texture {Hash}; no mip reduction required.", hash); + return; + } + + if (!performanceConfig.EnableIndexTextureDownscale) + { + _downscaledPaths[hash] = sourcePath; + _logger.LogTrace("Skipping downscale for index texture {Hash}; feature disabled.", hash); + return; + } + + if (onlyDownscaleUncompressed && headerInfo.HasValue && IsBlockCompressedFormat(headerInfo.Value.Format)) + { + _downscaledPaths[hash] = sourcePath; + _logger.LogTrace("Skipping downscale for index texture {Hash}; block compressed format {Format}.", hash, headerInfo.Value.Format); + return; + } + + using var sourceScratch = TexFileHelper.Load(sourcePath); + using var rgbaScratch = sourceScratch.GetRGBA(out var rgbaInfo).ThrowIfError(rgbaInfo); + + var bytesPerPixel = rgbaInfo.Meta.Format.BitsPerPixel() / 8; + var width = rgbaInfo.Meta.Width; + var height = rgbaInfo.Meta.Height; + var requiredLength = width * height * bytesPerPixel; + + var rgbaPixels = rgbaScratch.Pixels[..requiredLength].ToArray(); + using var originalImage = SixLabors.ImageSharp.Image.LoadPixelData(rgbaPixels, width, height); + + var targetSize = CalculateTargetSize(originalImage.Width, originalImage.Height, targetMaxDimension); + if (targetSize.width == originalImage.Width && targetSize.height == originalImage.Height) + { + return; + } + + using var resized = ReduceIndexTexture(originalImage, targetSize.width, targetSize.height); + + var resizedPixels = new byte[targetSize.width * targetSize.height * 4]; + resized.CopyPixelDataTo(resizedPixels); + + using var resizedScratch = ScratchImage.FromRGBA(resizedPixels, targetSize.width, targetSize.height, out var creationInfo).ThrowIfError(creationInfo); + using var finalScratch = resizedScratch.Convert(DXGIFormat.B8G8R8A8UNorm); + + TexFileHelper.Save(destination, finalScratch); + RegisterDownscaledTexture(hash, sourcePath, destination); + } + catch (Exception ex) + { + TryDelete(destination); + _logger.LogWarning( + ex, + "Texture downscale failed for {Hash} ({MapKind}) from {SourcePath} -> {Destination}. TargetMax={TargetMaxDimension}, OnlyUncompressed={OnlyDownscaleUncompressed}, IsIndex={IsIndexTexture}, HeaderFormat={HeaderFormat}", + hash, + mapKind, + sourcePath, + destination ?? "", + targetMaxDimension, + onlyDownscaleUncompressed, + isIndexTexture, + headerInfo?.Format); + } + finally + { + _activeJobs.TryRemove(hash, out _); + } + } + + private static (int width, int height) CalculateTargetSize(int width, int height, int targetMaxDimension) + { + var resultWidth = width; + var resultHeight = height; + + while (Math.Max(resultWidth, resultHeight) > targetMaxDimension) + { + resultWidth = Math.Max(BlockMultiple, resultWidth / 2); + resultHeight = Math.Max(BlockMultiple, resultHeight / 2); + } + + return (resultWidth, resultHeight); + } + + private static bool IsIndexMap(TextureMapKind kind) + => kind is TextureMapKind.Mask + or TextureMapKind.Index + or TextureMapKind.Ui; + + private Task TryDropTopMipAsync( + string hash, + string sourcePath, + string destination, + int targetMaxDimension, + bool onlyDownscaleUncompressed, + TexHeaderInfo? headerInfo = null) + { + TexHeaderInfo? header = headerInfo; + int dropCount = -1; + int originalWidth = 0; + int originalHeight = 0; + int originalMipLevels = 0; + + try + { + if (!File.Exists(sourcePath)) + { + _logger.LogWarning("Cannot trim mip levels for texture {Hash}; source path missing: {Path}", hash, sourcePath); + return Task.FromResult(false); + } + + if (header is null && TryReadTexHeader(sourcePath, out var discoveredHeader)) + { + header = discoveredHeader; + } + + if (header is TexHeaderInfo info) + { + if (onlyDownscaleUncompressed && IsBlockCompressedFormat(info.Format)) + { + _logger.LogTrace("Skipping mip trim for texture {Hash}; block compressed format {Format}.", hash, info.Format); + return Task.FromResult(false); + } + + if (info.MipLevels <= 1) + { + return Task.FromResult(false); + } + + var headerDepth = info.Depth == 0 ? 1 : info.Depth; + if (!ShouldTrimDimensions(info.Width, info.Height, headerDepth, targetMaxDimension)) + { + return Task.FromResult(false); + } + } + + using var original = TexFileHelper.Load(sourcePath); + var meta = original.Meta; + originalWidth = meta.Width; + originalHeight = meta.Height; + originalMipLevels = meta.MipLevels; + if (meta.MipLevels <= 1) + { + return Task.FromResult(false); + } + + if (!ShouldTrim(meta, targetMaxDimension)) + { + return Task.FromResult(false); + } + + var targetSize = CalculateTargetSize(meta.Width, meta.Height, targetMaxDimension); + dropCount = CalculateDropCount(meta, targetSize.width, targetSize.height); + if (dropCount <= 0) + { + return Task.FromResult(false); + } + + using var trimmed = TrimMipChain(original, dropCount); + TexFileHelper.Save(destination, trimmed); + RegisterDownscaledTexture(hash, sourcePath, destination); + _logger.LogDebug("Trimmed {DropCount} top mip level(s) for texture {Hash} -> {Path}", dropCount, hash, destination); + return Task.FromResult(true); + } + catch (Exception ex) + { + _logger.LogWarning( + ex, + "Failed to trim mips for texture {Hash} from {SourcePath} -> {Destination}. TargetMax={TargetMaxDimension}, OnlyUncompressed={OnlyDownscaleUncompressed}, HeaderFormat={HeaderFormat}, OriginalSize={OriginalWidth}x{OriginalHeight}, OriginalMipLevels={OriginalMipLevels}, DropAttempt={DropCount}", + hash, + sourcePath, + destination, + targetMaxDimension, + onlyDownscaleUncompressed, + header?.Format, + originalWidth, + originalHeight, + originalMipLevels, + dropCount); + TryDelete(destination); + return Task.FromResult(false); + } + } + + private static int CalculateDropCount(in TexMeta meta, int targetWidth, int targetHeight) + { + var drop = 0; + var width = meta.Width; + var height = meta.Height; + + while ((width > targetWidth || height > targetHeight) && drop + 1 < meta.MipLevels) + { + drop++; + width = ReduceDimension(width); + height = ReduceDimension(height); + } + + return drop; + } + + private static ScratchImage TrimMipChain(ScratchImage source, int dropCount) + { + var meta = source.Meta; + var newMeta = meta; + newMeta.MipLevels = meta.MipLevels - dropCount; + newMeta.Width = ReduceDimension(meta.Width, dropCount); + newMeta.Height = ReduceDimension(meta.Height, dropCount); + if (meta.Dimension == TexDimension.Tex3D) + { + newMeta.Depth = ReduceDimension(meta.Depth, dropCount); + } + + var result = ScratchImage.Initialize(newMeta); + CopyMipChainData(source, result, dropCount, meta); + return result; + } + + private static unsafe void CopyMipChainData(ScratchImage source, ScratchImage destination, int dropCount, in TexMeta sourceMeta) + { + var destinationMeta = destination.Meta; + var arraySize = Math.Max(1, sourceMeta.ArraySize); + var isCube = sourceMeta.IsCubeMap; + var isVolume = sourceMeta.Dimension == TexDimension.Tex3D; + + for (var item = 0; item < arraySize; item++) + { + for (var mip = 0; mip < destinationMeta.MipLevels; mip++) + { + var sourceMip = mip + dropCount; + var sliceCount = GetSliceCount(sourceMeta, sourceMip, isCube, isVolume); + + for (var slice = 0; slice < sliceCount; slice++) + { + var srcImage = source.GetImage(sourceMip, item, slice); + var dstImage = destination.GetImage(mip, item, slice); + CopyImage(srcImage, dstImage); + } + } + } + } + + private static int GetSliceCount(in TexMeta meta, int mip, bool isCube, bool isVolume) + { + if (isCube) + { + return 6; + } + + if (isVolume) + { + return Math.Max(1, meta.Depth >> mip); + } + + return 1; + } + + private static unsafe void CopyImage(in OtterImage source, in OtterImage destination) + { + var srcPtr = (byte*)source.Pixels; + var dstPtr = (byte*)destination.Pixels; + var bytesToCopy = Math.Min(source.SlicePitch, destination.SlicePitch); + Buffer.MemoryCopy(srcPtr, dstPtr, destination.SlicePitch, bytesToCopy); + } + + private static int ReduceDimension(int value, int iterations) + { + var result = value; + for (var i = 0; i < iterations; i++) + { + result = ReduceDimension(result); + } + + return result; + } + + private static int ReduceDimension(int value) + => value <= 1 ? 1 : Math.Max(1, value / 2); + + private static Image ReduceIndexTexture(Image source, int targetWidth, int targetHeight) + { + var current = source.Clone(); + + while (current.Width > targetWidth || current.Height > targetHeight) + { + var nextWidth = Math.Max(targetWidth, Math.Max(BlockMultiple, current.Width / 2)); + var nextHeight = Math.Max(targetHeight, Math.Max(BlockMultiple, current.Height / 2)); + var next = new Image(nextWidth, nextHeight); + + for (int y = 0; y < nextHeight; y++) + { + var srcY = Math.Min(current.Height - 1, y * 2); + for (int x = 0; x < nextWidth; x++) + { + var srcX = Math.Min(current.Width - 1, x * 2); + + var topLeft = current[srcX, srcY]; + var topRight = current[Math.Min(current.Width - 1, srcX + 1), srcY]; + var bottomLeft = current[srcX, Math.Min(current.Height - 1, srcY + 1)]; + var bottomRight = current[Math.Min(current.Width - 1, srcX + 1), Math.Min(current.Height - 1, srcY + 1)]; + + next[x, y] = DownscaleIndexBlock(topLeft, topRight, bottomLeft, bottomRight); + } + } + + current.Dispose(); + current = next; + } + + return current; + } + + private static Image ReduceLinearTexture(Image source, int targetWidth, int targetHeight) + { + var clone = source.Clone(); + + while (clone.Width > targetWidth || clone.Height > targetHeight) + { + var nextWidth = Math.Max(targetWidth, Math.Max(BlockMultiple, clone.Width / 2)); + var nextHeight = Math.Max(targetHeight, Math.Max(BlockMultiple, clone.Height / 2)); + clone.Mutate(ctx => ctx.Resize(nextWidth, nextHeight, KnownResamplers.Lanczos3)); + } + + return clone; + } + + private static Rgba32 DownscaleIndexBlock(in Rgba32 topLeft, in Rgba32 topRight, in Rgba32 bottomLeft, in Rgba32 bottomRight) + { + Span ordered = stackalloc Rgba32[4] + { + bottomLeft, + bottomRight, + topRight, + topLeft + }; + + Span weights = stackalloc float[4]; + var hasContribution = false; + + foreach (var sample in SampleOffsets) + { + if (TryAccumulateSampleWeights(ordered, sample, weights)) + { + hasContribution = true; + } + } + + if (hasContribution) + { + var bestIndex = IndexOfMax(weights); + if (bestIndex >= 0 && weights[bestIndex] > 0f) + { + return ordered[bestIndex]; + } + } + + Span fallback = stackalloc Rgba32[4] { topLeft, topRight, bottomLeft, bottomRight }; + return PickMajorityColor(fallback); + } + + private static readonly Vector2[] SampleOffsets = + { + new(0.25f, 0.25f), + new(0.75f, 0.25f), + new(0.25f, 0.75f), + new(0.75f, 0.75f), + }; + + private static bool TryAccumulateSampleWeights(ReadOnlySpan colors, in Vector2 sampleUv, Span weights) + { + var red = new Vector4( + colors[0].R / 255f, + colors[1].R / 255f, + colors[2].R / 255f, + colors[3].R / 255f); + + var symbols = QuantizeSymbols(red); + var cellUv = ComputeShiftedUv(sampleUv); + + Span order = stackalloc int[4]; + order[0] = 0; + order[1] = 1; + order[2] = 2; + order[3] = 3; + + ApplySymmetry(ref symbols, ref cellUv, order); + + var equality = BuildEquality(symbols, symbols.W); + var selector = BuildSelector(equality, symbols, cellUv); + + const uint lut = 0x00000C07u; + + if (((lut >> (int)selector) & 1u) != 0u) + { + weights[order[3]] += 1f; + return true; + } + + if (selector == 3u) + { + equality = BuildEquality(symbols, symbols.Z); + } + + var weight = ComputeWeight(equality, cellUv); + if (weight <= 1e-6f) + { + return false; + } + + var factor = 1f / weight; + + var wW = equality.W * (1f - cellUv.X) * (1f - cellUv.Y) * factor; + var wX = equality.X * (1f - cellUv.X) * cellUv.Y * factor; + var wZ = equality.Z * cellUv.X * (1f - cellUv.Y) * factor; + var wY = equality.Y * cellUv.X * cellUv.Y * factor; + + var contributed = false; + + if (wW > 0f) + { + weights[order[3]] += wW; + contributed = true; + } + + if (wX > 0f) + { + weights[order[0]] += wX; + contributed = true; + } + + if (wZ > 0f) + { + weights[order[2]] += wZ; + contributed = true; + } + + if (wY > 0f) + { + weights[order[1]] += wY; + contributed = true; + } + + return contributed; + } + + private static Vector4 QuantizeSymbols(in Vector4 channel) + => new( + Quantize(channel.X), + Quantize(channel.Y), + Quantize(channel.Z), + Quantize(channel.W)); + + private static float Quantize(float value) + { + var clamped = Math.Clamp(value, 0f, 1f); + return (MathF.Round(clamped * 16f) + 0.5f) / 16f; + } + + private static void ApplySymmetry(ref Vector4 symbols, ref Vector2 cellUv, Span order) + { + if (cellUv.X >= 0.5f) + { + symbols = SwapYxwz(symbols, order); + cellUv.X = 1f - cellUv.X; + } + + if (cellUv.Y >= 0.5f) + { + symbols = SwapWzyx(symbols, order); + cellUv.Y = 1f - cellUv.Y; + } + } + + private static Vector4 BuildEquality(in Vector4 symbols, float reference) + => new( + AreEqual(symbols.X, reference) ? 1f : 0f, + AreEqual(symbols.Y, reference) ? 1f : 0f, + AreEqual(symbols.Z, reference) ? 1f : 0f, + AreEqual(symbols.W, reference) ? 1f : 0f); + + private static uint BuildSelector(in Vector4 equality, in Vector4 symbols, in Vector2 cellUv) + { + uint selector = 0; + if (equality.X > 0.5f) selector |= 4u; + if (equality.Y > 0.5f) selector |= 8u; + if (equality.Z > 0.5f) selector |= 16u; + if (AreEqual(symbols.X, symbols.Z)) selector |= 2u; + if (cellUv.X + cellUv.Y >= 0.5f) selector |= 1u; + + return selector; + } + + private static float ComputeWeight(in Vector4 equality, in Vector2 cellUv) + => equality.W * (1f - cellUv.X) * (1f - cellUv.Y) + + equality.X * (1f - cellUv.X) * cellUv.Y + + equality.Z * cellUv.X * (1f - cellUv.Y) + + equality.Y * cellUv.X * cellUv.Y; + + private static Vector2 ComputeShiftedUv(in Vector2 uv) + { + var shifted = new Vector2( + uv.X - MathF.Floor(uv.X), + uv.Y - MathF.Floor(uv.Y)); + + shifted.X -= 0.5f; + if (shifted.X < 0f) + { + shifted.X += 1f; + } + + shifted.Y -= 0.5f; + if (shifted.Y < 0f) + { + shifted.Y += 1f; + } + + return shifted; + } + + private static Vector4 SwapYxwz(in Vector4 v, Span order) + { + var o0 = order[0]; + var o1 = order[1]; + var o2 = order[2]; + var o3 = order[3]; + + order[0] = o1; + order[1] = o0; + order[2] = o3; + order[3] = o2; + + return new Vector4(v.Y, v.X, v.W, v.Z); + } + + private static Vector4 SwapWzyx(in Vector4 v, Span order) + { + var o0 = order[0]; + var o1 = order[1]; + var o2 = order[2]; + var o3 = order[3]; + + order[0] = o3; + order[1] = o2; + order[2] = o1; + order[3] = o0; + + return new Vector4(v.W, v.Z, v.Y, v.X); + } + + private static int IndexOfMax(ReadOnlySpan values) + { + var bestIndex = -1; + var bestValue = 0f; + + for (var i = 0; i < values.Length; i++) + { + if (values[i] > bestValue) + { + bestValue = values[i]; + bestIndex = i; + } + } + + return bestIndex; + } + + private static bool AreEqual(float a, float b) => MathF.Abs(a - b) <= 1e-5f; + + private static Rgba32 PickMajorityColor(ReadOnlySpan colors) + { + var counts = new Dictionary(colors.Length); + foreach (var color in colors) + { + if (counts.TryGetValue(color, out var count)) + { + counts[color] = count + 1; + } + else + { + counts[color] = 1; + } + } + + return counts + .OrderByDescending(kvp => kvp.Value) + .ThenByDescending(kvp => kvp.Key.A) + .ThenByDescending(kvp => kvp.Key.R) + .ThenByDescending(kvp => kvp.Key.G) + .ThenByDescending(kvp => kvp.Key.B) + .First().Key; + } + + private static bool ShouldTrim(in TexMeta meta, int targetMaxDimension) + { + var depth = meta.Dimension == TexDimension.Tex3D ? Math.Max(1, meta.Depth) : 1; + return ShouldTrimDimensions(meta.Width, meta.Height, depth, targetMaxDimension); + } + + private static bool ShouldTrimDimensions(int width, int height, int depth, int targetMaxDimension) + { + if (width <= targetMaxDimension || height <= targetMaxDimension) + { + return false; + } + + if (depth > 1 && depth <= targetMaxDimension) + { + return false; + } + + return true; + } + + private int ResolveTargetMaxDimension() + { + var configured = _playerPerformanceConfigService.Current.TextureDownscaleMaxDimension; + if (configured <= 0) + { + return DefaultTargetMaxDimension; + } + + return Math.Clamp(configured, BlockMultiple, MaxSupportedTargetDimension); + } + + private readonly struct TexHeaderInfo + { + public TexHeaderInfo(ushort width, ushort height, ushort depth, ushort mipLevels, TexFile.TextureFormat format) + { + Width = width; + Height = height; + Depth = depth; + MipLevels = mipLevels; + Format = format; + } + + public ushort Width { get; } + public ushort Height { get; } + public ushort Depth { get; } + public ushort MipLevels { get; } + public TexFile.TextureFormat Format { get; } + } + + private static bool TryReadTexHeader(string path, out TexHeaderInfo header) + { + header = default; + + try + { + Span buffer = stackalloc byte[16]; + using var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); + var read = stream.Read(buffer); + if (read < buffer.Length) + { + return false; + } + + var formatValue = BinaryPrimitives.ReadInt32LittleEndian(buffer[4..8]); + var format = (TexFile.TextureFormat)formatValue; + var width = BinaryPrimitives.ReadUInt16LittleEndian(buffer[8..10]); + var height = BinaryPrimitives.ReadUInt16LittleEndian(buffer[10..12]); + var depth = BinaryPrimitives.ReadUInt16LittleEndian(buffer[12..14]); + var mipLevels = BinaryPrimitives.ReadUInt16LittleEndian(buffer[14..16]); + header = new TexHeaderInfo(width, height, depth, mipLevels, format); + return true; + } + catch + { + return false; + } + } + + private static bool IsBlockCompressedFormat(TexFile.TextureFormat format) + => TryGetCompressionTarget(format, out _); + + private static bool TryGetCompressionTarget(TexFile.TextureFormat format, out TextureCompressionTarget target) + { + if (BlockCompressedFormatMap.TryGetValue(unchecked((int)format), out var mapped)) + { + target = mapped; + return true; + } + + target = default; + return false; + } + + private void RegisterDownscaledTexture(string hash, string sourcePath, string destination) + { + _downscaledPaths[hash] = destination; + _logger.LogDebug("Downscaled texture {Hash} -> {Path}", hash, destination); + + var performanceConfig = _playerPerformanceConfigService.Current; + if (performanceConfig.KeepOriginalTextureFiles) + { + return; + } + + if (string.Equals(sourcePath, destination, StringComparison.OrdinalIgnoreCase)) + { + return; + } + + if (!TryReplaceCacheEntryWithDownscaled(hash, sourcePath, destination)) + { + return; + } + + TryDelete(sourcePath); + } + + private bool TryReplaceCacheEntryWithDownscaled(string hash, string sourcePath, string destination) + { + try + { + var cacheEntry = _fileCacheManager.GetFileCacheByHash(hash); + if (cacheEntry is null || !cacheEntry.IsCacheEntry) + { + return File.Exists(sourcePath) ? false : true; + } + + var cacheFolder = _configService.Current.CacheFolder; + if (string.IsNullOrEmpty(cacheFolder)) + { + return false; + } + + if (!destination.StartsWith(cacheFolder, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + var info = new FileInfo(destination); + if (!info.Exists) + { + return false; + } + + var relative = Path.GetRelativePath(cacheFolder, destination) + .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + var sanitizedRelative = relative.TrimStart(Path.DirectorySeparatorChar); + var prefixed = Path.Combine(FileCacheManager.CachePrefix, sanitizedRelative); + + var replacement = new FileCacheEntity( + hash, + prefixed, + info.LastWriteTimeUtc.Ticks.ToString(CultureInfo.InvariantCulture), + info.Length, + cacheEntry.CompressedSize); + replacement.SetResolvedFilePath(destination); + + if (!string.Equals(cacheEntry.PrefixedFilePath, prefixed, StringComparison.OrdinalIgnoreCase)) + { + _fileCacheManager.RemoveHashedFile(cacheEntry.Hash, cacheEntry.PrefixedFilePath); + } + + _fileCacheManager.UpdateHashedFile(replacement, computeProperties: false); + _fileCacheManager.WriteOutFullCsv(); + + _logger.LogTrace("Replaced cache entry for texture {Hash} to downscaled path {Path}", hash, destination); + return true; + } + catch (Exception ex) + { + _logger.LogTrace(ex, "Failed to replace cache entry for texture {Hash}", hash); + return false; + } + } + + private string? GetExistingDownscaledPath(string hash) + { + var candidate = Path.Combine(GetDownscaledDirectory(), $"{hash}.tex"); + return File.Exists(candidate) ? candidate : null; + } + + private string GetDownscaledDirectory() + { + var directory = Path.Combine(_configService.Current.CacheFolder, "downscaled"); + if (!Directory.Exists(directory)) + { + try + { + Directory.CreateDirectory(directory); + } + catch (Exception ex) + { + _logger.LogTrace(ex, "Failed to create downscaled directory {Directory}", directory); + } + } + + return directory; + } + + private static void TryDelete(string? path) + { + if (string.IsNullOrEmpty(path)) return; + try + { + if (File.Exists(path)) + { + File.Delete(path); + } + } + catch + { + // ignored + } + } + +} diff --git a/LightlessSync/Services/TextureCompression/TextureMapKind.cs b/LightlessSync/Services/TextureCompression/TextureMapKind.cs new file mode 100644 index 0000000..ed2dee1 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureMapKind.cs @@ -0,0 +1,13 @@ +namespace LightlessSync.Services.TextureCompression; + +public enum TextureMapKind +{ + Diffuse, + Normal, + Specular, + Mask, + Index, + Emissive, + Ui, + Unknown +} diff --git a/LightlessSync/Services/TextureCompression/TextureMetadataHelper.cs b/LightlessSync/Services/TextureCompression/TextureMetadataHelper.cs new file mode 100644 index 0000000..3c0934c --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureMetadataHelper.cs @@ -0,0 +1,549 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Dalamud.Plugin.Services; +using Microsoft.Extensions.Logging; +using Penumbra.Api.Enums; +using Penumbra.GameData.Files; + +namespace LightlessSync.Services.TextureCompression; + +// ima lie, this isn't garbage + +public sealed class TextureMetadataHelper +{ + private readonly ILogger _logger; + private readonly IDataManager _dataManager; + + private static readonly Dictionary RecommendationCatalog = new() + { + [TextureCompressionTarget.BC1] = ( + "BC1 (Simple Compression for Opaque RGB)", + "This offers a 8:1 compression ratio and is quick with acceptable quality, but only supports RGB, without Alpha.\n\nCan be used for diffuse maps and equipment textures to save extra space."), + [TextureCompressionTarget.BC3] = ( + "BC3 (Simple Compression for RGBA)", + "This offers a 4:1 compression ratio and is quick with acceptable quality, and fully supports RGBA.\n\nGeneric format that can be used for most textures."), + [TextureCompressionTarget.BC4] = ( + "BC4 (Simple Compression for Opaque Grayscale)", + "This offers a 8:1 compression ratio and has almost indistinguishable quality, but only supports Grayscale, without Alpha.\n\nCan be used for face paints and legacy marks."), + [TextureCompressionTarget.BC5] = ( + "BC5 (Simple Compression for Opaque RG)", + "This offers a 4:1 compression ratio and has almost indistinguishable quality, but only supports RG, without B or Alpha.\n\nRecommended for index maps, unrecommended for normal maps."), + [TextureCompressionTarget.BC7] = ( + "BC7 (Complex Compression for RGBA)", + "This offers a 4:1 compression ratio and has almost indistinguishable quality, but may take a while.\n\nGeneric format that can be used for most textures.") + }; + + private static readonly (TextureUsageCategory Category, string Token)[] CategoryTokens = + { + (TextureUsageCategory.Ui, "/ui/"), + (TextureUsageCategory.Ui, "/uld/"), + (TextureUsageCategory.Ui, "/icon/"), + + (TextureUsageCategory.VisualEffect, "/vfx/"), + + (TextureUsageCategory.Customization, "/chara/human/"), + (TextureUsageCategory.Customization, "/chara/common/"), + (TextureUsageCategory.Customization, "/chara/bibo"), + + (TextureUsageCategory.Weapon, "/chara/weapon/"), + + (TextureUsageCategory.Accessory, "/chara/accessory/"), + + (TextureUsageCategory.Gear, "/chara/equipment/"), + + (TextureUsageCategory.Monster, "/chara/monster/"), + (TextureUsageCategory.Monster, "/chara/demihuman/"), + + (TextureUsageCategory.MountOrMinion, "/chara/mount/"), + (TextureUsageCategory.MountOrMinion, "/chara/battlepet/"), + + (TextureUsageCategory.Companion, "/chara/companion/"), + + (TextureUsageCategory.Housing, "/hou/"), + (TextureUsageCategory.Housing, "/housing/"), + (TextureUsageCategory.Housing, "/bg/"), + (TextureUsageCategory.Housing, "/bgcommon/") + }; + + private static readonly (TextureUsageCategory Category, string SlotToken, string SlotName)[] SlotTokens = + { + (TextureUsageCategory.Gear, "_met", "Head"), + + (TextureUsageCategory.Gear, "_top", "Body"), + + (TextureUsageCategory.Gear, "_glv", "Hands"), + + (TextureUsageCategory.Gear, "_dwn", "Legs"), + + (TextureUsageCategory.Gear, "_sho", "Feet"), + + (TextureUsageCategory.Accessory, "_ear", "Ears"), + + (TextureUsageCategory.Accessory, "_nek", "Neck"), + + (TextureUsageCategory.Accessory, "_wrs", "Wrists"), + + (TextureUsageCategory.Accessory, "_rir", "Ring"), + + (TextureUsageCategory.Weapon, "_w", "Weapon"), // sussy + (TextureUsageCategory.Weapon, "weapon", "Weapon"), + }; + + private static readonly (TextureMapKind Kind, string Token)[] MapTokens = + { + (TextureMapKind.Normal, "_n"), + (TextureMapKind.Normal, "_normal"), + (TextureMapKind.Normal, "_norm"), + + (TextureMapKind.Mask, "_m"), + (TextureMapKind.Mask, "_mask"), + (TextureMapKind.Mask, "_msk"), + + (TextureMapKind.Specular, "_s"), + (TextureMapKind.Specular, "_spec"), + + (TextureMapKind.Emissive, "_em"), + (TextureMapKind.Emissive, "_glow"), + + (TextureMapKind.Index, "_id"), + (TextureMapKind.Index, "_idx"), + (TextureMapKind.Index, "_index"), + (TextureMapKind.Index, "_multi"), + + (TextureMapKind.Diffuse, "_d"), + (TextureMapKind.Diffuse, "_diff"), + (TextureMapKind.Diffuse, "_b"), + (TextureMapKind.Diffuse, "_base") + }; + + private const string TextureSegment = "/texture/"; + private const string MaterialSegment = "/material/"; + + private const uint NormalSamplerId = 0x0C5EC1F1u; + private const uint IndexSamplerId = 0x565F8FD8u; + private const uint SpecularSamplerId = 0x2B99E025u; + private const uint DiffuseSamplerId = 0x115306BEu; + private const uint MaskSamplerId = 0x8A4E82B6u; + + public TextureMetadataHelper(ILogger logger, IDataManager dataManager) + { + _logger = logger; + _dataManager = dataManager; + } + + public bool TryGetRecommendationInfo(TextureCompressionTarget target, out (string Title, string Description) info) + => RecommendationCatalog.TryGetValue(target, out info); + + public TextureUsageCategory DetermineCategory(string? gamePath) + { + var normalized = Normalize(gamePath); + if (string.IsNullOrEmpty(normalized)) + return TextureUsageCategory.Unknown; + + var fileName = Path.GetFileName(normalized); + if (!string.IsNullOrEmpty(fileName)) + { + if (fileName.StartsWith("bibo", StringComparison.OrdinalIgnoreCase) + || fileName.Contains("gen3", StringComparison.OrdinalIgnoreCase) + || fileName.Contains("tfgen3", StringComparison.OrdinalIgnoreCase)) + { + return TextureUsageCategory.Customization; + } + } + + if (normalized.Contains("bibo", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("skin", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("gen3", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("tfgen3", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("body", StringComparison.OrdinalIgnoreCase)) + { + return TextureUsageCategory.Customization; + } + + foreach (var (category, token) in CategoryTokens) + { + if (normalized.Contains(token, StringComparison.OrdinalIgnoreCase)) + return category; + } + + var segments = normalized.Split('/', StringSplitOptions.RemoveEmptyEntries); + if (segments.Length >= 2 && string.Equals(segments[0], "chara", StringComparison.OrdinalIgnoreCase)) + { + return segments[1] switch + { + "equipment" => TextureUsageCategory.Gear, + "accessory" => TextureUsageCategory.Accessory, + "weapon" => TextureUsageCategory.Weapon, + "human" or "common" => TextureUsageCategory.Customization, + "monster" or "demihuman" => TextureUsageCategory.Monster, + "mount" or "battlepet" => TextureUsageCategory.MountOrMinion, + "companion" => TextureUsageCategory.Companion, + _ => TextureUsageCategory.Unknown + }; + } + + if (normalized.StartsWith("chara/", StringComparison.OrdinalIgnoreCase) + && (normalized.Contains("bibo", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("skin", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("body", StringComparison.OrdinalIgnoreCase))) + return TextureUsageCategory.Customization; + + return TextureUsageCategory.Unknown; + } + + public string DetermineSlot(TextureUsageCategory category, string? gamePath) + { + if (category == TextureUsageCategory.Customization) + return GuessCustomizationSlot(gamePath); + + var normalized = Normalize(gamePath); + var fileName = Path.GetFileNameWithoutExtension(normalized); + var searchSource = $"{normalized} {fileName}".ToLowerInvariant(); + + foreach (var (candidateCategory, token, slot) in SlotTokens) + { + if (candidateCategory == category && searchSource.Contains(token, StringComparison.Ordinal)) + return slot; + } + + return category switch + { + TextureUsageCategory.Gear => "Gear", + TextureUsageCategory.Accessory => "Accessory", + TextureUsageCategory.Weapon => "Weapon", + TextureUsageCategory.Monster => "Monster", + TextureUsageCategory.MountOrMinion => "Mount / Minion", + TextureUsageCategory.Companion => "Companion", + TextureUsageCategory.VisualEffect => "VFX", + TextureUsageCategory.Housing => "Housing", + TextureUsageCategory.Ui => "UI", + _ => "General" + }; + } + + public TextureMapKind DetermineMapKind(string path) + => DetermineMapKind(path, null); + + public TextureMapKind DetermineMapKind(string? gamePath, string? localTexturePath) + { + if (TryDetermineFromMaterials(gamePath, localTexturePath, out var kind)) + return kind; + + return GuessMapFromFileName(gamePath ?? localTexturePath ?? string.Empty); + } + + private bool TryDetermineFromMaterials(string? gamePath, string? localTexturePath, out TextureMapKind kind) + { + kind = TextureMapKind.Unknown; + + var candidates = new List(); + AddGameMaterialCandidates(gamePath, candidates); + AddLocalMaterialCandidates(localTexturePath, candidates); + + if (candidates.Count == 0) + return false; + + var normalizedGamePath = Normalize(gamePath); + var normalizedFileName = Path.GetFileName(normalizedGamePath); + + foreach (var candidate in candidates) + { + if (!TryLoadMaterial(candidate, out var material)) + continue; + + if (TryInferKindFromMaterial(material, normalizedGamePath, normalizedFileName, out kind)) + return true; + } + + return false; + } + + private void AddGameMaterialCandidates(string? gamePath, IList candidates) + { + var normalized = Normalize(gamePath); + if (string.IsNullOrEmpty(normalized)) + return; + + var textureIndex = normalized.IndexOf(TextureSegment, StringComparison.Ordinal); + if (textureIndex < 0) + return; + + var prefix = normalized[..textureIndex]; + var suffix = normalized[(textureIndex + TextureSegment.Length)..]; + var baseName = Path.GetFileNameWithoutExtension(suffix); + if (string.IsNullOrEmpty(baseName)) + return; + + var directory = $"{prefix}{MaterialSegment}{Path.GetDirectoryName(suffix)?.Replace('\\', '/') ?? string.Empty}".TrimEnd('/'); + candidates.Add(MaterialCandidate.Game($"{directory}/mt_{baseName}.mtrl")); + + if (baseName.StartsWith('v') && baseName.IndexOf('_') is > 0 and var idx) + { + var trimmed = baseName[(idx + 1)..]; + candidates.Add(MaterialCandidate.Game($"{directory}/mt_{trimmed}.mtrl")); + } + } + + private void AddLocalMaterialCandidates(string? localTexturePath, IList candidates) + { + if (string.IsNullOrEmpty(localTexturePath)) + return; + + var normalized = localTexturePath.Replace('\\', '/'); + var textureIndex = normalized.IndexOf(TextureSegment, StringComparison.OrdinalIgnoreCase); + if (textureIndex >= 0) + { + var prefix = normalized[..textureIndex]; + var suffix = normalized[(textureIndex + TextureSegment.Length)..]; + var folder = Path.GetDirectoryName(suffix)?.Replace('\\', '/') ?? string.Empty; + var baseName = Path.GetFileNameWithoutExtension(suffix); + if (!string.IsNullOrEmpty(baseName)) + { + var materialDir = $"{prefix}{MaterialSegment}{folder}".TrimEnd('/'); + candidates.Add(MaterialCandidate.Local(Path.Combine(materialDir.Replace('/', Path.DirectorySeparatorChar), $"mt_{baseName}.mtrl"))); + + if (baseName.StartsWith('v') && baseName.IndexOf('_') is > 0 and var idx) + { + var trimmed = baseName[(idx + 1)..]; + candidates.Add(MaterialCandidate.Local(Path.Combine(materialDir.Replace('/', Path.DirectorySeparatorChar), $"mt_{trimmed}.mtrl"))); + } + } + } + + var textureDirectory = Path.GetDirectoryName(localTexturePath); + if (!string.IsNullOrEmpty(textureDirectory) && Directory.Exists(textureDirectory)) + { + foreach (var candidate in Directory.EnumerateFiles(textureDirectory, "*.mtrl", SearchOption.TopDirectoryOnly)) + candidates.Add(MaterialCandidate.Local(candidate)); + } + } + + private bool TryLoadMaterial(MaterialCandidate candidate, out MtrlFile material) + { + material = null!; + + try + { + switch (candidate.Source) + { + case MaterialSource.Game: + var gameFile = _dataManager.GetFile(candidate.Path); + if (gameFile?.Data.Length > 0) + { + material = new MtrlFile(gameFile.Data); + return material.Valid; + } + break; + + case MaterialSource.Local when File.Exists(candidate.Path): + material = new MtrlFile(File.ReadAllBytes(candidate.Path)); + return material.Valid; + } + } + catch (Exception ex) + { + _logger.LogDebug(ex, "Failed to load material {Path}", candidate.Path); + } + + return false; + } + + private static bool TryInferKindFromMaterial(MtrlFile material, string normalizedGamePath, string? fileName, out TextureMapKind kind) + { + kind = TextureMapKind.Unknown; + var targetName = fileName ?? string.Empty; + + foreach (var sampler in material.ShaderPackage.Samplers) + { + if (!TryMapSamplerId(sampler.SamplerId, out var candidateKind)) + continue; + + if (sampler.TextureIndex < 0 || sampler.TextureIndex >= material.Textures.Length) + continue; + + var texturePath = Normalize(material.Textures[sampler.TextureIndex].Path); + + if (!string.IsNullOrEmpty(normalizedGamePath) && string.Equals(texturePath, normalizedGamePath, StringComparison.OrdinalIgnoreCase)) + { + kind = candidateKind; + return true; + } + + if (!string.IsNullOrEmpty(targetName) && string.Equals(Path.GetFileName(texturePath), targetName, StringComparison.OrdinalIgnoreCase)) + { + kind = candidateKind; + return true; + } + } + + return false; + } + + private static TextureMapKind GuessMapFromFileName(string path) + { + var normalized = Normalize(path); + var fileName = Path.GetFileNameWithoutExtension(normalized); + if (string.IsNullOrEmpty(fileName)) + return TextureMapKind.Unknown; + + foreach (var (kind, token) in MapTokens) + { + if (fileName.Contains(token, StringComparison.OrdinalIgnoreCase)) + return kind; + } + + return TextureMapKind.Unknown; + } + + public bool TryMapFormatToTarget(string? format, out TextureCompressionTarget target) + { + var normalized = (format ?? string.Empty).ToUpperInvariant(); + if (normalized.Contains("BC1", StringComparison.Ordinal)) + { + target = TextureCompressionTarget.BC1; + return true; + } + + if (normalized.Contains("BC3", StringComparison.Ordinal)) + { + target = TextureCompressionTarget.BC3; + return true; + } + + if (normalized.Contains("BC4", StringComparison.Ordinal)) + { + target = TextureCompressionTarget.BC4; + return true; + } + + if (normalized.Contains("BC5", StringComparison.Ordinal)) + { + target = TextureCompressionTarget.BC5; + return true; + } + + if (normalized.Contains("BC7", StringComparison.Ordinal)) + { + target = TextureCompressionTarget.BC7; + return true; + } + + target = TextureCompressionTarget.BC7; + return false; + } + + public (TextureCompressionTarget Target, string Reason)? GetSuggestedTarget(string? format, TextureMapKind mapKind) + { + TextureCompressionTarget? current = null; + if (TryMapFormatToTarget(format, out var mapped)) + current = mapped; + + var suggestion = mapKind switch + { + TextureMapKind.Normal => TextureCompressionTarget.BC7, + TextureMapKind.Mask => TextureCompressionTarget.BC4, + TextureMapKind.Index => TextureCompressionTarget.BC3, + TextureMapKind.Specular => TextureCompressionTarget.BC4, + TextureMapKind.Emissive => TextureCompressionTarget.BC3, + TextureMapKind.Diffuse => TextureCompressionTarget.BC7, + _ => TextureCompressionTarget.BC7 + }; + + if (mapKind == TextureMapKind.Diffuse && !HasAlphaHint(format)) + suggestion = TextureCompressionTarget.BC1; + + if (current == suggestion) + return null; + + return (suggestion, RecommendationCatalog.TryGetValue(suggestion, out var info) + ? info.Description + : "Suggested to balance visual quality and file size."); + } + + private static bool TryMapSamplerId(uint id, out TextureMapKind kind) + { + kind = id switch + { + NormalSamplerId => TextureMapKind.Normal, + IndexSamplerId => TextureMapKind.Index, + SpecularSamplerId => TextureMapKind.Specular, + DiffuseSamplerId => TextureMapKind.Diffuse, + MaskSamplerId => TextureMapKind.Mask, + _ => TextureMapKind.Unknown + }; + + return kind != TextureMapKind.Unknown; + } + + private static string GuessCustomizationSlot(string? gamePath) + { + var normalized = Normalize(gamePath); + var fileName = Path.GetFileName(normalized); + + if (!string.IsNullOrEmpty(fileName)) + { + if (fileName.StartsWith("bibo", StringComparison.OrdinalIgnoreCase) + || fileName.Contains("gen3", StringComparison.OrdinalIgnoreCase) + || fileName.Contains("tfgen3", StringComparison.OrdinalIgnoreCase) + || fileName.Contains("skin", StringComparison.OrdinalIgnoreCase)) + { + return "Skin"; + } + } + + if (normalized.Contains("hair", StringComparison.OrdinalIgnoreCase)) + return "Hair"; + if (normalized.Contains("face", StringComparison.OrdinalIgnoreCase)) + return "Face"; + if (normalized.Contains("tail", StringComparison.OrdinalIgnoreCase)) + return "Tail"; + if (normalized.Contains("zear", StringComparison.OrdinalIgnoreCase)) + return "Ear"; + if (normalized.Contains("eye", StringComparison.OrdinalIgnoreCase)) + return "Eye"; + if (normalized.Contains("body", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("skin", StringComparison.OrdinalIgnoreCase) + || normalized.Contains("bibo", StringComparison.OrdinalIgnoreCase)) + return "Skin"; + if (normalized.Contains("decal_face", StringComparison.OrdinalIgnoreCase)) + return "Face Paint"; + if (normalized.Contains("decal_equip", StringComparison.OrdinalIgnoreCase)) + return "Equipment Decal"; + + return "Customization"; + } + + private static bool HasAlphaHint(string? format) + { + if (string.IsNullOrEmpty(format)) + return false; + + var normalized = format.ToUpperInvariant(); + return normalized.Contains("A8", StringComparison.Ordinal) + || normalized.Contains("ARGB", StringComparison.Ordinal) + || normalized.Contains("BC3", StringComparison.Ordinal) + || normalized.Contains("BC7", StringComparison.Ordinal); + } + + private static string Normalize(string? path) + { + if (string.IsNullOrWhiteSpace(path)) + return string.Empty; + + return path.Replace('\\', '/').ToLowerInvariant(); + } + + private readonly record struct MaterialCandidate(string Path, MaterialSource Source) + { + public static MaterialCandidate Game(string path) => new(path, MaterialSource.Game); + public static MaterialCandidate Local(string path) => new(path, MaterialSource.Local); + } + + private enum MaterialSource + { + Game, + Local + } +} diff --git a/LightlessSync/Services/TextureCompression/TextureUsageCategory.cs b/LightlessSync/Services/TextureCompression/TextureUsageCategory.cs new file mode 100644 index 0000000..c4af7b7 --- /dev/null +++ b/LightlessSync/Services/TextureCompression/TextureUsageCategory.cs @@ -0,0 +1,16 @@ +namespace LightlessSync.Services.TextureCompression; + +public enum TextureUsageCategory +{ + Gear, + Weapon, + Accessory, + Customization, + MountOrMinion, + Companion, + Monster, + Housing, + Ui, + VisualEffect, + Unknown +} diff --git a/LightlessSync/Services/UiFactory.cs b/LightlessSync/Services/UiFactory.cs index 248eae0..435d3c2 100644 --- a/LightlessSync/Services/UiFactory.cs +++ b/LightlessSync/Services/UiFactory.cs @@ -1,10 +1,13 @@ -using Dalamud.Interface.ImGuiFileDialog; +using Dalamud.Interface.ImGuiFileDialog; +using LightlessSync.API.Data; using LightlessSync.API.Dto.Group; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; using LightlessSync.UI; +using LightlessSync.UI.Tags; using LightlessSync.WebAPI; +using LightlessSync.UI.Services; using Microsoft.Extensions.Logging; namespace LightlessSync.Services; @@ -15,42 +18,131 @@ public class UiFactory private readonly LightlessMediator _lightlessMediator; private readonly ApiController _apiController; private readonly UiSharedService _uiSharedService; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly ServerConfigurationManager _serverConfigManager; private readonly LightlessProfileManager _lightlessProfileManager; private readonly PerformanceCollectorService _performanceCollectorService; private readonly FileDialogManager _fileDialogManager; + private readonly ProfileTagService _profileTagService; - public UiFactory(ILoggerFactory loggerFactory, LightlessMediator lightlessMediator, ApiController apiController, - UiSharedService uiSharedService, PairManager pairManager, ServerConfigurationManager serverConfigManager, - LightlessProfileManager lightlessProfileManager, PerformanceCollectorService performanceCollectorService, FileDialogManager fileDialogManager) + public UiFactory( + ILoggerFactory loggerFactory, + LightlessMediator lightlessMediator, + ApiController apiController, + UiSharedService uiSharedService, + PairUiService pairUiService, + ServerConfigurationManager serverConfigManager, + LightlessProfileManager lightlessProfileManager, + PerformanceCollectorService performanceCollectorService, + FileDialogManager fileDialogManager, + ProfileTagService profileTagService) { _loggerFactory = loggerFactory; _lightlessMediator = lightlessMediator; _apiController = apiController; _uiSharedService = uiSharedService; - _pairManager = pairManager; + _pairUiService = pairUiService; _serverConfigManager = serverConfigManager; _lightlessProfileManager = lightlessProfileManager; _performanceCollectorService = performanceCollectorService; _fileDialogManager = fileDialogManager; + _profileTagService = profileTagService; } public SyncshellAdminUI CreateSyncshellAdminUi(GroupFullInfoDto dto) { - return new SyncshellAdminUI(_loggerFactory.CreateLogger(), _lightlessMediator, - _apiController, _uiSharedService, _pairManager, dto, _performanceCollectorService, _lightlessProfileManager, _fileDialogManager); + return new SyncshellAdminUI( + _loggerFactory.CreateLogger(), + _lightlessMediator, + _apiController, + _uiSharedService, + _pairUiService, + dto, + _performanceCollectorService, + _lightlessProfileManager, + _fileDialogManager); } public StandaloneProfileUi CreateStandaloneProfileUi(Pair pair) { - return new StandaloneProfileUi(_loggerFactory.CreateLogger(), _lightlessMediator, - _uiSharedService, _serverConfigManager, _lightlessProfileManager, _pairManager, pair, _performanceCollectorService); + return new StandaloneProfileUi( + _loggerFactory.CreateLogger(), + _lightlessMediator, + _uiSharedService, + _serverConfigManager, + _profileTagService, + _lightlessProfileManager, + _pairUiService, + pair, + pair.UserData, + null, + false, + null, + _performanceCollectorService); + } + + public StandaloneProfileUi CreateStandaloneProfileUi(UserData userData) + { + return new StandaloneProfileUi( + _loggerFactory.CreateLogger(), + _lightlessMediator, + _uiSharedService, + _serverConfigManager, + _profileTagService, + _lightlessProfileManager, + _pairUiService, + null, + userData, + null, + false, + null, + _performanceCollectorService); + } + + public StandaloneProfileUi CreateLightfinderProfileUi(UserData userData, string hashedCid) + { + return new StandaloneProfileUi( + _loggerFactory.CreateLogger(), + _lightlessMediator, + _uiSharedService, + _serverConfigManager, + _profileTagService, + _lightlessProfileManager, + _pairUiService, + null, + userData, + null, + true, + hashedCid, + _performanceCollectorService); + } + + public StandaloneProfileUi CreateStandaloneGroupProfileUi(GroupFullInfoDto groupInfo) + { + return new StandaloneProfileUi( + _loggerFactory.CreateLogger(), + _lightlessMediator, + _uiSharedService, + _serverConfigManager, + _profileTagService, + _lightlessProfileManager, + _pairUiService, + null, + null, + groupInfo, + false, + null, + _performanceCollectorService); } public PermissionWindowUI CreatePermissionPopupUi(Pair pair) { - return new PermissionWindowUI(_loggerFactory.CreateLogger(), pair, - _lightlessMediator, _uiSharedService, _apiController, _performanceCollectorService); + return new PermissionWindowUI( + _loggerFactory.CreateLogger(), + pair, + _lightlessMediator, + _uiSharedService, + _apiController, + _performanceCollectorService); } } diff --git a/LightlessSync/Services/UiService.cs b/LightlessSync/Services/UiService.cs index f08b1fc..4951bec 100644 --- a/LightlessSync/Services/UiService.cs +++ b/LightlessSync/Services/UiService.cs @@ -2,6 +2,7 @@ using Dalamud.Interface; using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.Windowing; using LightlessSync.LightlessConfiguration; +using LightlessSync.PlayerData.Factories; using LightlessSync.Services.Mediator; using LightlessSync.UI; using LightlessSync.UI.Style; @@ -18,12 +19,13 @@ public sealed class UiService : DisposableMediatorSubscriberBase private readonly LightlessConfigService _lightlessConfigService; private readonly WindowSystem _windowSystem; private readonly UiFactory _uiFactory; + private readonly PairFactory _pairFactory; public UiService(ILogger logger, IUiBuilder uiBuilder, LightlessConfigService lightlessConfigService, WindowSystem windowSystem, IEnumerable windows, UiFactory uiFactory, FileDialogManager fileDialogManager, - LightlessMediator lightlessMediator) : base(logger, lightlessMediator) + LightlessMediator lightlessMediator, PairFactory pairFactory) : base(logger, lightlessMediator) { _logger = logger; _logger.LogTrace("Creating {type}", GetType().Name); @@ -31,6 +33,7 @@ public sealed class UiService : DisposableMediatorSubscriberBase _lightlessConfigService = lightlessConfigService; _windowSystem = windowSystem; _uiFactory = uiFactory; + _pairFactory = pairFactory; _fileDialogManager = fileDialogManager; _uiBuilder.DisableGposeUiHide = true; @@ -45,10 +48,101 @@ public sealed class UiService : DisposableMediatorSubscriberBase Mediator.Subscribe(this, (msg) => { + var resolvedPair = _pairFactory.Create(msg.Pair.UniqueIdent) ?? msg.Pair; if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui - && string.Equals(ui.Pair.UserData.AliasOrUID, msg.Pair.UserData.AliasOrUID, StringComparison.Ordinal))) + && ui.Pair != null + && ui.Pair.UniqueIdent == resolvedPair.UniqueIdent)) { - var window = _uiFactory.CreateStandaloneProfileUi(msg.Pair); + var window = _uiFactory.CreateStandaloneProfileUi(resolvedPair); + _createdWindows.Add(window); + _windowSystem.AddWindow(window); + } + }); + + Mediator.Subscribe(this, msg => + { + var existingWindow = _createdWindows.Find(p => p is StandaloneProfileUi ui + && ui.IsGroupProfile + && ui.ProfileGroupData is not null + && string.Equals(ui.ProfileGroupData.GID, msg.Group.Group.GID, StringComparison.Ordinal)); + + if (existingWindow is StandaloneProfileUi existing) + { + existing.IsOpen = true; + } + else + { + var window = _uiFactory.CreateStandaloneGroupProfileUi(msg.Group); + _createdWindows.Add(window); + _windowSystem.AddWindow(window); + } + }); + + Mediator.Subscribe(this, msg => + { + var window = _createdWindows.Find(p => p is StandaloneProfileUi ui + && ui.IsGroupProfile + && ui.ProfileGroupData is not null + && string.Equals(ui.ProfileGroupData.GID, msg.Group.Group.GID, StringComparison.Ordinal)); + + if (window is not null) + { + _windowSystem.RemoveWindow(window); + _createdWindows.Remove(window); + window.Dispose(); + } + }); + + Mediator.Subscribe(this, msg => + { + if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui + && ui.Pair is null + && !ui.IsGroupProfile + && !ui.IsLightfinderContext + && string.Equals(ui.ProfileUserData.UID, msg.User.UID, StringComparison.Ordinal))) + { + var window = _uiFactory.CreateStandaloneProfileUi(msg.User); + _createdWindows.Add(window); + _windowSystem.AddWindow(window); + } + }); + + Mediator.Subscribe(this, msg => + { + var window = _createdWindows.Find(p => p is StandaloneProfileUi ui + && ui.Pair is null + && !ui.IsGroupProfile + && !ui.IsLightfinderContext + && string.Equals(ui.ProfileUserData.UID, msg.User.UID, StringComparison.Ordinal)); + + if (window is not null) + { + _windowSystem.RemoveWindow(window); + _createdWindows.Remove(window); + window.Dispose(); + } + }); + + Mediator.Subscribe(this, msg => + { + if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui && ui.IsLightfinderContext && string.Equals(ui.LightfinderCid, msg.HashedCid, StringComparison.Ordinal))) + { + var window = _uiFactory.CreateLightfinderProfileUi(msg.User, msg.HashedCid); + _createdWindows.Add(window); + _windowSystem.AddWindow(window); + } + }); + + Mediator.Subscribe(this, msg => + { + if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui + && !ui.IsLightfinderContext + && !ui.IsGroupProfile + && ui.Pair is null + && ui.ProfileUserData is not null + && string.Equals(ui.ProfileUserData.UID, msg.User.UID, StringComparison.Ordinal))) + { + var window = _uiFactory.CreateStandaloneProfileUi(msg.User); _createdWindows.Add(window); _windowSystem.AddWindow(window); } @@ -67,10 +161,12 @@ public sealed class UiService : DisposableMediatorSubscriberBase Mediator.Subscribe(this, (msg) => { + var resolvedPair = _pairFactory.Create(msg.Pair.UniqueIdent) ?? msg.Pair; if (!_createdWindows.Exists(p => p is PermissionWindowUI ui - && msg.Pair == ui.Pair)) + && ui.Pair is not null + && ui.Pair.UniqueIdent == resolvedPair.UniqueIdent)) { - var window = _uiFactory.CreatePermissionPopupUi(msg.Pair); + var window = _uiFactory.CreatePermissionPopupUi(resolvedPair); _createdWindows.Add(window); _windowSystem.AddWindow(window); } diff --git a/LightlessSync/UI/BroadcastUI.cs b/LightlessSync/UI/BroadcastUI.cs index c760a45..c008f31 100644 --- a/LightlessSync/UI/BroadcastUI.cs +++ b/LightlessSync/UI/BroadcastUI.cs @@ -143,9 +143,9 @@ namespace LightlessSync.UI _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"),"This lets other Lightless users know you use Lightless. While enabled, you and others using Lightfinder can see each other identified as Lightless users."); ImGui.Indent(15f); - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); - ImGui.Text("- This is done using a 'Lightless' label above player nameplates."); - ImGui.PopStyleColor(); + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); + ImGui.Text("- This is done using a 'Lightless' label above player nameplates."); + ImGui.PopStyleColor(); ImGui.Unindent(15f); ImGuiHelpers.ScaledDummy(3f); @@ -369,7 +369,7 @@ namespace LightlessSync.UI ImGui.EndTabItem(); } - #if DEBUG +#if DEBUG if (ImGui.BeginTabItem("Debug")) { ImGui.Text("Broadcast Cache"); @@ -428,7 +428,7 @@ namespace LightlessSync.UI ImGui.EndTabItem(); } - #endif +#endif ImGui.EndTabBar(); } diff --git a/LightlessSync/UI/CharaDataHubUi.McdOnline.cs b/LightlessSync/UI/CharaDataHubUi.McdOnline.cs index e86ef10..dc6b572 100644 --- a/LightlessSync/UI/CharaDataHubUi.McdOnline.cs +++ b/LightlessSync/UI/CharaDataHubUi.McdOnline.cs @@ -795,11 +795,12 @@ internal sealed partial class CharaDataHubUi { UiSharedService.DrawTree("Access for Specific Individuals / Syncshells", () => { + var snapshot = _pairUiService.GetSnapshot(); using (ImRaii.PushId("user")) { using (ImRaii.Group()) { - InputComboHybrid("##AliasToAdd", "##AliasToAddPicker", ref _specificIndividualAdd, _pairManager.PairsWithGroups.Keys, + InputComboHybrid("##AliasToAdd", "##AliasToAddPicker", ref _specificIndividualAdd, snapshot.PairsWithGroups.Keys, static pair => (pair.UserData.UID, pair.UserData.Alias, pair.UserData.AliasOrUID, pair.GetNote())); ImGui.SameLine(); using (ImRaii.Disabled(string.IsNullOrEmpty(_specificIndividualAdd) @@ -868,8 +869,8 @@ internal sealed partial class CharaDataHubUi { using (ImRaii.Group()) { - InputComboHybrid("##GroupAliasToAdd", "##GroupAliasToAddPicker", ref _specificGroupAdd, _pairManager.Groups.Keys, - group => (group.GID, group.Alias, group.AliasOrGID, _serverConfigurationManager.GetNoteForGid(group.GID))); + InputComboHybrid("##GroupAliasToAdd", "##GroupAliasToAddPicker", ref _specificGroupAdd, snapshot.Groups, + group => (group.GID, group.GroupAliasOrGID, group.GroupAliasOrGID, _serverConfigurationManager.GetNoteForGid(group.GID))); ImGui.SameLine(); using (ImRaii.Disabled(string.IsNullOrEmpty(_specificGroupAdd) || updateDto.GroupList.Any(f => string.Equals(f.GID, _specificGroupAdd, StringComparison.Ordinal) || string.Equals(f.Alias, _specificGroupAdd, StringComparison.Ordinal)))) diff --git a/LightlessSync/UI/CharaDataHubUi.cs b/LightlessSync/UI/CharaDataHubUi.cs index 51723b9..b50b819 100644 --- a/LightlessSync/UI/CharaDataHubUi.cs +++ b/LightlessSync/UI/CharaDataHubUi.cs @@ -7,7 +7,6 @@ using Dalamud.Interface.Utility.Raii; using LightlessSync.API.Dto.CharaData; using LightlessSync.LightlessConfiguration; using LightlessSync.LightlessConfiguration.Models; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.CharaData; using LightlessSync.Services.CharaData.Models; @@ -15,6 +14,8 @@ using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; using LightlessSync.Utils; using Microsoft.Extensions.Logging; +using LightlessSync.UI.Services; +using LightlessSync.PlayerData.Pairs; namespace LightlessSync.UI; @@ -26,7 +27,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase private readonly CharaDataConfigService _configService; private readonly DalamudUtilService _dalamudUtilService; private readonly FileDialogManager _fileDialogManager; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly CharaDataGposeTogetherManager _charaDataGposeTogetherManager; private readonly ServerConfigurationManager _serverConfigurationManager; private readonly UiSharedService _uiSharedService; @@ -77,7 +78,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase public CharaDataHubUi(ILogger logger, LightlessMediator mediator, PerformanceCollectorService performanceCollectorService, CharaDataManager charaDataManager, CharaDataNearbyManager charaDataNearbyManager, CharaDataConfigService configService, UiSharedService uiSharedService, ServerConfigurationManager serverConfigurationManager, - DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager, PairManager pairManager, + DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager, PairUiService pairUiService, CharaDataGposeTogetherManager charaDataGposeTogetherManager) : base(logger, mediator, "Lightless Sync Character Data Hub###LightlessSyncCharaDataUI", performanceCollectorService) { @@ -90,7 +91,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase _serverConfigurationManager = serverConfigurationManager; _dalamudUtilService = dalamudUtilService; _fileDialogManager = fileDialogManager; - _pairManager = pairManager; + _pairUiService = pairUiService; _charaDataGposeTogetherManager = charaDataGposeTogetherManager; Mediator.Subscribe(this, (_) => IsOpen |= _configService.Current.OpenLightlessHubOnGposeStart); Mediator.Subscribe(this, (msg) => diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index cc8d326..40b0f0e 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -16,6 +16,8 @@ using LightlessSync.Services.ServerConfiguration; using LightlessSync.UI.Components; using LightlessSync.UI.Handlers; using LightlessSync.UI.Models; +using LightlessSync.UI.Services; +using LightlessSync.UI.Style; using LightlessSync.Utils; using LightlessSync.WebAPI; using LightlessSync.WebAPI.Files; @@ -38,11 +40,12 @@ public class CompactUi : WindowMediatorSubscriberBase private readonly ApiController _apiController; private readonly LightlessConfigService _configService; private readonly LightlessMediator _lightlessMediator; + private readonly PairLedger _pairLedger; private readonly ConcurrentDictionary> _currentDownloads = new(); private readonly DrawEntityFactory _drawEntityFactory; private readonly FileUploadManager _fileTransferManager; private readonly PlayerPerformanceConfigService _playerPerformanceConfig; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly SelectTagForPairUi _selectTagForPairUi; private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi; private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; @@ -65,13 +68,15 @@ public class CompactUi : WindowMediatorSubscriberBase private float _transferPartHeight; private bool _wasOpen; private float _windowContentWidth; + private readonly SeluneBrush _seluneBrush = new(); + private const float ConnectButtonHighlightThickness = 14f; public CompactUi( ILogger logger, UiSharedService uiShared, LightlessConfigService configService, ApiController apiController, - PairManager pairManager, + PairUiService pairUiService, ServerConfigurationManager serverManager, LightlessMediator mediator, FileUploadManager fileTransferManager, @@ -87,12 +92,12 @@ public class CompactUi : WindowMediatorSubscriberBase IpcManager ipcManager, BroadcastService broadcastService, CharacterAnalyzer characterAnalyzer, - PlayerPerformanceConfigService playerPerformanceConfig, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, NotificationService lightlessNotificationService) : base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService) + PlayerPerformanceConfigService playerPerformanceConfig, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, NotificationService lightlessNotificationService, PairLedger pairLedger) : base(logger, mediator, "###LightlessSyncMainUI", performanceCollectorService) { _uiSharedService = uiShared; _configService = configService; _apiController = apiController; - _pairManager = pairManager; + _pairUiService = pairUiService; _serverManager = serverManager; _fileTransferManager = fileTransferManager; _tagHandler = tagHandler; @@ -105,7 +110,8 @@ public class CompactUi : WindowMediatorSubscriberBase _renamePairTagUi = renameTagUi; _ipcManager = ipcManager; _broadcastService = broadcastService; - _tabMenu = new TopTabMenu(Mediator, _apiController, _pairManager, _uiSharedService, pairRequestService, dalamudUtilService, lightlessNotificationService); + _pairLedger = pairLedger; + _tabMenu = new TopTabMenu(Mediator, _apiController, _uiSharedService, pairRequestService, dalamudUtilService, lightlessNotificationService); AllowPinning = true; AllowClickthrough = false; @@ -176,6 +182,11 @@ public class CompactUi : WindowMediatorSubscriberBase protected override void DrawInternal() { + var drawList = ImGui.GetWindowDrawList(); + var windowPos = ImGui.GetWindowPos(); + var windowSize = ImGui.GetWindowSize(); + using var selune = Selune.Begin(_seluneBrush, drawList, windowPos, windowSize); + _windowContentWidth = UiSharedService.GetWindowContentRegionWidth(); if (!_apiController.IsCurrentVersion) { @@ -223,29 +234,47 @@ public class CompactUi : WindowMediatorSubscriberBase using (ImRaii.PushId("header")) DrawUIDHeader(); _uiSharedService.RoundedSeparator(UIColors.Get("LightlessPurple"), 2.5f, 1f, 12f); - using (ImRaii.PushId("serverstatus")) DrawServerStatus(); + using (ImRaii.PushId("serverstatus")) + { + DrawServerStatus(); + } + selune.DrawHighlightOnly(ImGui.GetIO().DeltaTime); + var style = ImGui.GetStyle(); + var contentMinY = windowPos.Y + ImGui.GetWindowContentRegionMin().Y; + var gradientInset = 4f * ImGuiHelpers.GlobalScale; + var gradientTop = MathF.Max(contentMinY, ImGui.GetCursorScreenPos().Y - style.ItemSpacing.Y + gradientInset); ImGui.Separator(); if (_apiController.ServerState is ServerState.Connected) { - using (ImRaii.PushId("global-topmenu")) _tabMenu.Draw(); + var pairSnapshot = _pairUiService.GetSnapshot(); + + using (ImRaii.PushId("global-topmenu")) _tabMenu.Draw(pairSnapshot); using (ImRaii.PushId("pairlist")) DrawPairs(); ImGui.Separator(); + var transfersTop = ImGui.GetCursorScreenPos().Y; + var gradientBottom = MathF.Max(gradientTop, transfersTop - style.ItemSpacing.Y - gradientInset); + selune.DrawGradient(gradientTop, gradientBottom, ImGui.GetIO().DeltaTime); float pairlistEnd = ImGui.GetCursorPosY(); using (ImRaii.PushId("transfers")) DrawTransfers(); _transferPartHeight = ImGui.GetCursorPosY() - pairlistEnd - ImGui.GetTextLineHeight(); - using (ImRaii.PushId("group-pair-popup")) _selectPairsForGroupUi.Draw(_pairManager.DirectPairs); - using (ImRaii.PushId("group-syncshell-popup")) _selectSyncshellForTagUi.Draw([.. _pairManager.Groups.Values]); + using (ImRaii.PushId("group-pair-popup")) _selectPairsForGroupUi.Draw(pairSnapshot.DirectPairs); + using (ImRaii.PushId("group-syncshell-popup")) _selectSyncshellForTagUi.Draw(pairSnapshot.Groups); using (ImRaii.PushId("group-pair-edit")) _renamePairTagUi.Draw(); using (ImRaii.PushId("group-syncshell-edit")) _renameSyncshellTagUi.Draw(); using (ImRaii.PushId("grouping-pair-popup")) _selectTagForPairUi.Draw(); using (ImRaii.PushId("grouping-syncshell-popup")) _selectTagForSyncshellUi.Draw(); } - - if (_configService.Current.OpenPopupOnAdd && _pairManager.LastAddedUser != null) + else { - _lastAddedUser = _pairManager.LastAddedUser; - _pairManager.LastAddedUser = null; + selune.Animate(ImGui.GetIO().DeltaTime); + } + + var lastAddedPair = _pairUiService.GetLastAddedPair(); + if (_configService.Current.OpenPopupOnAdd && lastAddedPair is not null) + { + _lastAddedUser = lastAddedPair; + _pairUiService.ClearLastAddedPair(); ImGui.OpenPopup("Set Notes for New User"); _showModalForUserAddition = true; _lastAddedUserComment = string.Empty; @@ -290,15 +319,17 @@ public class CompactUi : WindowMediatorSubscriberBase : (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y + ImGui.GetTextLineHeight() - ImGui.GetStyle().WindowPadding.Y - ImGui.GetStyle().WindowBorderSize) - _transferPartHeight - ImGui.GetCursorPosY(); - ImGui.BeginChild("list", new Vector2(_windowContentWidth, ySize), border: false); - - foreach (var item in _drawFolders) + if (ImGui.BeginChild("list", new Vector2(_windowContentWidth, ySize), border: false)) { - item.Draw(); + foreach (var item in _drawFolders) + { + item.Draw(); + } } ImGui.EndChild(); } + private void DrawServerStatus() { var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link); @@ -371,6 +402,19 @@ public class CompactUi : WindowMediatorSubscriberBase } } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight( + ImGui.GetItemRectMin(), + ImGui.GetItemRectMax(), + SeluneHighlightMode.Both, + borderOnly: true, + borderThicknessOverride: ConnectButtonHighlightThickness, + exactSize: true, + clipToElement: true, + roundingOverride: ImGui.GetStyle().FrameRounding); + } + UiSharedService.AttachToolTip(isConnectingOrConnected ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName); } } @@ -527,6 +571,17 @@ public class CompactUi : WindowMediatorSubscriberBase if (ImGui.IsItemHovered()) { + var padding = new Vector2(10f * ImGuiHelpers.GlobalScale); + Selune.RegisterHighlight( + ImGui.GetItemRectMin() - padding, + ImGui.GetItemRectMax() + padding, + SeluneHighlightMode.Point, + exactSize: true, + clipToElement: true, + clipPadding: padding, + highlightColorOverride: UIColors.Get("LightlessGreen"), + highlightAlphaOverride: 0.2f); + ImGui.BeginTooltip(); ImGui.PushTextWrapPos(ImGui.GetFontSize() * 32f); @@ -603,6 +658,20 @@ public class CompactUi : WindowMediatorSubscriberBase } } + if (ImGui.IsItemHovered()) + { + var padding = new Vector2(35f * ImGuiHelpers.GlobalScale); + Selune.RegisterHighlight( + ImGui.GetItemRectMin() - padding, + ImGui.GetItemRectMax() + padding, + SeluneHighlightMode.Point, + exactSize: true, + clipToElement: true, + clipPadding: padding, + highlightColorOverride: vanityGlowColor, + highlightAlphaOverride: 0.05f); + } + headerItemClicked = ImGui.IsItemClicked(); if (headerItemClicked) @@ -675,6 +744,20 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.TextColored(GetUidColor(), _apiController.UID); } + if (ImGui.IsItemHovered()) + { + var padding = new Vector2(30f * ImGuiHelpers.GlobalScale); + Selune.RegisterHighlight( + ImGui.GetItemRectMin() - padding, + ImGui.GetItemRectMax() + padding, + SeluneHighlightMode.Point, + exactSize: true, + clipToElement: true, + clipPadding: padding, + highlightColorOverride: vanityGlowColor, + highlightAlphaOverride: 0.05f); + } + bool uidFooterClicked = ImGui.IsItemClicked(); UiSharedService.AttachToolTip("Click to copy"); if (uidFooterClicked) @@ -696,28 +779,45 @@ public class CompactUi : WindowMediatorSubscriberBase var drawFolders = new List(); var filter = _tabMenu.Filter; - var allPairs = _pairManager.PairsWithGroups.ToDictionary(k => k.Key, k => k.Value); - var filteredPairs = allPairs.Where(p => PassesFilter(p.Key, filter)).ToDictionary(k => k.Key, k => k.Value); + var allEntries = _drawEntityFactory.GetAllEntries().ToList(); + var filteredEntries = string.IsNullOrEmpty(filter) + ? allEntries + : allEntries.Where(e => PassesFilter(e, filter)).ToList(); + + var syncshells = _pairLedger.GetAllSyncshells(); + var groupInfos = syncshells.Values + .Select(s => s.GroupFullInfo) + .OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase) + .ToList(); + + var entryLookup = allEntries.ToDictionary(e => e.DisplayEntry.Ident.UserId, StringComparer.Ordinal); + var filteredEntryLookup = filteredEntries.ToDictionary(e => e.DisplayEntry.Ident.UserId, StringComparer.Ordinal); //Filter of online/visible pairs if (_configService.Current.ShowVisibleUsersSeparately) { - var allVisiblePairs = ImmutablePairList(allPairs.Where(p => FilterVisibleUsers(p.Key))); - var filteredVisiblePairs = BasicSortedDictionary(filteredPairs.Where(p => FilterVisibleUsers(p.Key))); - - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomVisibleTag, filteredVisiblePairs, allVisiblePairs)); + var allVisiblePairs = SortVisibleEntries(allEntries.Where(FilterVisibleUsers)); + if (allVisiblePairs.Count > 0) + { + var filteredVisiblePairs = SortVisibleEntries(filteredEntries.Where(FilterVisibleUsers)); + drawFolders.Add(_drawEntityFactory.CreateTagFolder(TagHandler.CustomVisibleTag, filteredVisiblePairs, allVisiblePairs)); + } } //Filter of not foldered syncshells var groupFolders = new List(); - foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) + foreach (var group in groupInfos) { - GetGroups(allPairs, filteredPairs, group, out ImmutableList allGroupPairs, out Dictionary> filteredGroupPairs); - - if (FilterNotTaggedSyncshells(group)) + if (!FilterNotTaggedSyncshells(group)) { - groupFolders.Add(new GroupFolder(group, _drawEntityFactory.CreateDrawGroupFolder(group, filteredGroupPairs, allGroupPairs))); + continue; } + + var allGroupEntries = ResolveGroupEntries(entryLookup, syncshells, group, applyFilters: false); + var filteredGroupEntries = ResolveGroupEntries(filteredEntryLookup, syncshells, group, applyFilters: true); + // Always create the folder so empty syncshells remain visible in the UI. + var drawGroupFolder = _drawEntityFactory.CreateGroupFolder(group.Group.GID, group, filteredGroupEntries, allGroupEntries); + groupFolders.Add(new GroupFolder(group, drawGroupFolder)); } //Filter of grouped up syncshells (All Syncshells Folder) @@ -730,123 +830,215 @@ public class CompactUi : WindowMediatorSubscriberBase //Filter of grouped/foldered pairs foreach (var tag in _tagHandler.GetAllPairTagsSorted()) { - var allTagPairs = ImmutablePairList(allPairs.Where(p => FilterTagUsers(p.Key, tag))); - var filteredTagPairs = BasicSortedDictionary(filteredPairs.Where(p => FilterTagUsers(p.Key, tag) && FilterOnlineOrPausedSelf(p.Key))); - - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(tag, filteredTagPairs, allTagPairs)); + var allTagPairs = SortEntries(allEntries.Where(e => FilterTagUsers(e, tag))); + if (allTagPairs.Count > 0) + { + var filteredTagPairs = SortEntries(filteredEntries.Where(e => FilterTagUsers(e, tag) && FilterOnlineOrPausedSelf(e))); + drawFolders.Add(_drawEntityFactory.CreateTagFolder(tag, filteredTagPairs, allTagPairs)); + } } //Filter of grouped/foldered syncshells foreach (var syncshellTag in _tagHandler.GetAllSyncshellTagsSorted()) { var syncshellFolderTags = new List(); - foreach (var group in _pairManager.GroupPairs.Select(g => g.Key).OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)) + foreach (var group in groupInfos) { - if (_tagHandler.HasSyncshellTag(group.GID, syncshellTag)) + if (!_tagHandler.HasSyncshellTag(group.Group.GID, syncshellTag)) { - GetGroups(allPairs, filteredPairs, group, - out ImmutableList allGroupPairs, - out Dictionary> filteredGroupPairs); - - syncshellFolderTags.Add(new GroupFolder(group, _drawEntityFactory.CreateDrawGroupFolder($"tag_{group.GID}", group, filteredGroupPairs, allGroupPairs))); + continue; } + + var allGroupEntries = ResolveGroupEntries(entryLookup, syncshells, group, applyFilters: false); + var filteredGroupEntries = ResolveGroupEntries(filteredEntryLookup, syncshells, group, applyFilters: true); + // Keep tagged syncshells rendered regardless of whether membership info has loaded. + var taggedGroupFolder = _drawEntityFactory.CreateGroupFolder($"tag_{group.Group.GID}", group, filteredGroupEntries, allGroupEntries); + syncshellFolderTags.Add(new GroupFolder(group, taggedGroupFolder)); } drawFolders.Add(new DrawGroupedGroupFolder(syncshellFolderTags, _tagHandler, _apiController, _uiSharedService, _selectSyncshellForTagUi, _renameSyncshellTagUi, syncshellTag)); } //Filter of not grouped/foldered and offline pairs - var allOnlineNotTaggedPairs = ImmutablePairList(allPairs.Where(p => FilterNotTaggedUsers(p.Key))); - var onlineNotTaggedPairs = BasicSortedDictionary(filteredPairs.Where(p => FilterNotTaggedUsers(p.Key) && FilterOnlineOrPausedSelf(p.Key))); + var allOnlineNotTaggedPairs = SortEntries(allEntries.Where(FilterNotTaggedUsers)); + var onlineNotTaggedPairs = SortEntries(filteredEntries.Where(e => FilterNotTaggedUsers(e) && FilterOnlineOrPausedSelf(e))); - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder((_configService.Current.ShowOfflineUsersSeparately ? TagHandler.CustomOnlineTag : TagHandler.CustomAllTag), onlineNotTaggedPairs, allOnlineNotTaggedPairs)); + if (allOnlineNotTaggedPairs.Count > 0) + { + drawFolders.Add(_drawEntityFactory.CreateTagFolder( + _configService.Current.ShowOfflineUsersSeparately ? TagHandler.CustomOnlineTag : TagHandler.CustomAllTag, + onlineNotTaggedPairs, + allOnlineNotTaggedPairs)); + } if (_configService.Current.ShowOfflineUsersSeparately) { - var allOfflinePairs = ImmutablePairList(allPairs.Where(p => FilterOfflineUsers(p.Key, p.Value))); - var filteredOfflinePairs = BasicSortedDictionary(filteredPairs.Where(p => FilterOfflineUsers(p.Key, p.Value))); - - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomOfflineTag, filteredOfflinePairs, allOfflinePairs)); + var allOfflinePairs = SortEntries(allEntries.Where(FilterOfflineUsers)); + if (allOfflinePairs.Count > 0) + { + var filteredOfflinePairs = SortEntries(filteredEntries.Where(FilterOfflineUsers)); + drawFolders.Add(_drawEntityFactory.CreateTagFolder(TagHandler.CustomOfflineTag, filteredOfflinePairs, allOfflinePairs)); + } if (_configService.Current.ShowSyncshellOfflineUsersSeparately) { - var allOfflineSyncshellUsers = ImmutablePairList(allPairs.Where(p => FilterOfflineSyncshellUsers(p.Key))); - var filteredOfflineSyncshellUsers = BasicSortedDictionary(filteredPairs.Where(p => FilterOfflineSyncshellUsers(p.Key))); - - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomOfflineSyncshellTag, filteredOfflineSyncshellUsers, allOfflineSyncshellUsers)); + var allOfflineSyncshellUsers = SortEntries(allEntries.Where(FilterOfflineSyncshellUsers)); + if (allOfflineSyncshellUsers.Count > 0) + { + var filteredOfflineSyncshellUsers = SortEntries(filteredEntries.Where(FilterOfflineSyncshellUsers)); + drawFolders.Add(_drawEntityFactory.CreateTagFolder(TagHandler.CustomOfflineSyncshellTag, filteredOfflineSyncshellUsers, allOfflineSyncshellUsers)); + } } } - //Unpaired - drawFolders.Add(_drawEntityFactory.CreateDrawTagFolder(TagHandler.CustomUnpairedTag, - BasicSortedDictionary(filteredPairs.Where(p => p.Key.IsOneSidedPair)), - ImmutablePairList(allPairs.Where(p => p.Key.IsOneSidedPair)))); + //Unpaired + var unpairedAllEntries = SortEntries(allEntries.Where(e => e.IsOneSided)); + if (unpairedAllEntries.Count > 0) + { + var unpairedFiltered = SortEntries(filteredEntries.Where(e => e.IsOneSided)); + drawFolders.Add(_drawEntityFactory.CreateTagFolder(TagHandler.CustomUnpairedTag, unpairedFiltered, unpairedAllEntries)); + } return drawFolders; } } - private static bool PassesFilter(Pair pair, string filter) + private bool PassesFilter(PairUiEntry entry, string filter) { if (string.IsNullOrEmpty(filter)) return true; - return pair.UserData.AliasOrUID.Contains(filter, StringComparison.OrdinalIgnoreCase) || (pair.GetNote()?.Contains(filter, StringComparison.OrdinalIgnoreCase) ?? false) || (pair.PlayerName?.Contains(filter, StringComparison.OrdinalIgnoreCase) ?? false); + return entry.AliasOrUid.Contains(filter, StringComparison.OrdinalIgnoreCase) + || (!string.IsNullOrEmpty(entry.Note) && entry.Note.Contains(filter, StringComparison.OrdinalIgnoreCase)) + || (!string.IsNullOrEmpty(entry.DisplayName) && entry.DisplayName.Contains(filter, StringComparison.OrdinalIgnoreCase)); } - private string AlphabeticalSortKey(Pair pair) + private string AlphabeticalSortKey(PairUiEntry entry) { - if (_configService.Current.ShowCharacterNameInsteadOfNotesForVisible && !string.IsNullOrEmpty(pair.PlayerName)) + if (_configService.Current.ShowCharacterNameInsteadOfNotesForVisible && !string.IsNullOrEmpty(entry.DisplayName)) { - return _configService.Current.PreferNotesOverNamesForVisible ? (pair.GetNote() ?? string.Empty) : pair.PlayerName; + return _configService.Current.PreferNotesOverNamesForVisible ? (entry.Note ?? string.Empty) : entry.DisplayName; } - return pair.GetNote() ?? pair.UserData.AliasOrUID; + return !string.IsNullOrEmpty(entry.Note) ? entry.Note : entry.AliasOrUid; } - private bool FilterOnlineOrPausedSelf(Pair pair) => pair.IsOnline || (!pair.IsOnline && !_configService.Current.ShowOfflineUsersSeparately) || pair.UserPair.OwnPermissions.IsPaused(); + private bool FilterOnlineOrPausedSelf(PairUiEntry entry) => entry.IsOnline || (!entry.IsOnline && !_configService.Current.ShowOfflineUsersSeparately) || entry.SelfPermissions.IsPaused(); - private bool FilterVisibleUsers(Pair pair) => pair.IsVisible && (_configService.Current.ShowSyncshellUsersInVisible || pair.IsDirectlyPaired); + private bool FilterVisibleUsers(PairUiEntry entry) => entry.IsVisible && entry.IsOnline && (_configService.Current.ShowSyncshellUsersInVisible || entry.IsDirectlyPaired); - private bool FilterTagUsers(Pair pair, string tag) => pair.IsDirectlyPaired && !pair.IsOneSidedPair && _tagHandler.HasPairTag(pair.UserData.UID, tag); + private bool FilterTagUsers(PairUiEntry entry, string tag) => entry.IsDirectlyPaired && !entry.IsOneSided && _tagHandler.HasPairTag(entry.DisplayEntry.Ident.UserId, tag); - private static bool FilterGroupUsers(List groups, GroupFullInfoDto group) => groups.Exists(g => string.Equals(g.GID, group.GID, StringComparison.Ordinal)); - - private bool FilterNotTaggedUsers(Pair pair) => pair.IsDirectlyPaired && !pair.IsOneSidedPair && !_tagHandler.HasAnyPairTag(pair.UserData.UID); + private bool FilterNotTaggedUsers(PairUiEntry entry) => entry.IsDirectlyPaired && !entry.IsOneSided && !_tagHandler.HasAnyPairTag(entry.DisplayEntry.Ident.UserId); private bool FilterNotTaggedSyncshells(GroupFullInfoDto group) => !_tagHandler.HasAnySyncshellTag(group.GID) || _configService.Current.ShowGroupedSyncshellsInAll; - private bool FilterOfflineUsers(Pair pair, List groups) => ((pair.IsDirectlyPaired && _configService.Current.ShowSyncshellOfflineUsersSeparately) || !_configService.Current.ShowSyncshellOfflineUsersSeparately) && (!pair.IsOneSidedPair || groups.Count != 0) && !pair.IsOnline && !pair.UserPair.OwnPermissions.IsPaused(); - - private static bool FilterOfflineSyncshellUsers(Pair pair) => !pair.IsDirectlyPaired && !pair.IsOnline && !pair.UserPair.OwnPermissions.IsPaused(); - - private Dictionary> BasicSortedDictionary(IEnumerable>> pairs) => pairs.OrderByDescending(u => u.Key.IsVisible).ThenByDescending(u => u.Key.IsOnline).ThenBy(u => AlphabeticalSortKey(u.Key), StringComparer.OrdinalIgnoreCase).ToDictionary(u => u.Key, u => u.Value); - - private static ImmutableList ImmutablePairList(IEnumerable>> pairs) => [.. pairs.Select(k => k.Key)]; - - private void GetGroups(Dictionary> allPairs, - Dictionary> filteredPairs, - GroupFullInfoDto group, - out ImmutableList allGroupPairs, - out Dictionary> filteredGroupPairs) + private bool FilterOfflineUsers(PairUiEntry entry) { - allGroupPairs = ImmutablePairList(allPairs - .Where(u => FilterGroupUsers(u.Value, group))); + var groups = entry.DisplayEntry.Groups; + var includeDirect = _configService.Current.ShowSyncshellOfflineUsersSeparately ? entry.IsDirectlyPaired : true; + var includeGroup = !entry.IsOneSided || groups.Count != 0; + return includeDirect && includeGroup && !entry.IsOnline && !entry.SelfPermissions.IsPaused(); + } - filteredGroupPairs = filteredPairs - .Where(u => FilterGroupUsers(u.Value, group) && FilterOnlineOrPausedSelf(u.Key)) - .OrderByDescending(u => u.Key.IsOnline) - .ThenBy(u => - { - if (string.Equals(u.Key.UserData.UID, group.OwnerUID, StringComparison.Ordinal)) return 0; - if (group.GroupPairUserInfos.TryGetValue(u.Key.UserData.UID, out var info)) - { - if (info.IsModerator()) return 1; - if (info.IsPinned()) return 2; - } - return u.Key.IsVisible ? 3 : 4; - }) - .ThenBy(u => AlphabeticalSortKey(u.Key), StringComparer.OrdinalIgnoreCase) - .ToDictionary(k => k.Key, k => k.Value); + private static bool FilterOfflineSyncshellUsers(PairUiEntry entry) => !entry.IsDirectlyPaired && !entry.IsOnline && !entry.SelfPermissions.IsPaused(); + + private ImmutableList SortEntries(IEnumerable entries) + { + return entries + .OrderByDescending(e => e.IsVisible) + .ThenByDescending(e => e.IsOnline) + .ThenBy(e => AlphabeticalSortKey(e), StringComparer.OrdinalIgnoreCase) + .ToImmutableList(); + } + + private ImmutableList SortVisibleEntries(IEnumerable entries) + { + var entryList = entries.ToList(); + return _configService.Current.VisiblePairSortMode switch + { + VisiblePairSortMode.VramUsage => SortVisibleByMetric(entryList, e => e.LastAppliedApproximateVramBytes), + VisiblePairSortMode.EffectiveVramUsage => SortVisibleByMetric(entryList, e => e.LastAppliedApproximateEffectiveVramBytes), + VisiblePairSortMode.TriangleCount => SortVisibleByMetric(entryList, e => e.LastAppliedDataTris), + VisiblePairSortMode.Alphabetical => entryList + .OrderBy(e => AlphabeticalSortKey(e), StringComparer.OrdinalIgnoreCase) + .ToImmutableList(), + VisiblePairSortMode.PreferredDirectPairs => SortVisibleByPreferred(entryList), + _ => SortEntries(entryList), + }; + } + + private ImmutableList SortVisibleByMetric(IEnumerable entries, Func selector) + { + return entries + .OrderByDescending(entry => selector(entry) >= 0) + .ThenByDescending(selector) + .ThenByDescending(entry => entry.IsOnline) + .ThenBy(entry => AlphabeticalSortKey(entry), StringComparer.OrdinalIgnoreCase) + .ToImmutableList(); + } + + private ImmutableList SortVisibleByPreferred(IEnumerable entries) + { + return entries + .OrderByDescending(entry => entry.IsDirectlyPaired && entry.SelfPermissions.IsSticky()) + .ThenByDescending(entry => entry.IsDirectlyPaired) + .ThenByDescending(entry => entry.IsOnline) + .ThenBy(entry => AlphabeticalSortKey(entry), StringComparer.OrdinalIgnoreCase) + .ToImmutableList(); + } + + private ImmutableList SortGroupEntries(IEnumerable entries, GroupFullInfoDto group) + { + return entries + .OrderByDescending(e => e.IsOnline) + .ThenBy(e => GroupSortWeight(e, group)) + .ThenBy(e => AlphabeticalSortKey(e), StringComparer.OrdinalIgnoreCase) + .ToImmutableList(); + } + + private int GroupSortWeight(PairUiEntry entry, GroupFullInfoDto group) + { + if (string.Equals(entry.DisplayEntry.Ident.UserId, group.OwnerUID, StringComparison.Ordinal)) + { + return 0; + } + + if (group.GroupPairUserInfos.TryGetValue(entry.DisplayEntry.Ident.UserId, out var info)) + { + if (info.IsModerator()) return 1; + if (info.IsPinned()) return 2; + } + + return entry.IsVisible ? 3 : 4; + } + + private ImmutableList ResolveGroupEntries( + IReadOnlyDictionary entryLookup, + IReadOnlyDictionary syncshells, + GroupFullInfoDto group, + bool applyFilters) + { + if (!syncshells.TryGetValue(group.Group.GID, out var shell)) + { + return ImmutableList.Empty; + } + + var entries = shell.Users.Keys + .Select(id => entryLookup.TryGetValue(id, out var entry) ? entry : null) + .Where(entry => entry is not null) + .Cast(); + + if (applyFilters && _configService.Current.ShowOfflineUsersSeparately) + { + entries = entries.Where(entry => !FilterOfflineUsers(entry)); + } + + if (applyFilters && _configService.Current.ShowSyncshellOfflineUsersSeparately) + { + entries = entries.Where(entry => !FilterOfflineSyncshellUsers(entry)); + } + + return SortGroupEntries(entries, group); } private string GetServerError() diff --git a/LightlessSync/UI/Components/DrawFolderBase.cs b/LightlessSync/UI/Components/DrawFolderBase.cs index 15d558e..40330c7 100644 --- a/LightlessSync/UI/Components/DrawFolderBase.cs +++ b/LightlessSync/UI/Components/DrawFolderBase.cs @@ -1,9 +1,11 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; -using LightlessSync.PlayerData.Pairs; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Models; using System.Collections.Immutable; +using LightlessSync.UI; +using LightlessSync.UI.Style; namespace LightlessSync.UI.Components; @@ -11,16 +13,18 @@ public abstract class DrawFolderBase : IDrawFolder { public IImmutableList DrawPairs { get; init; } protected readonly string _id; - protected readonly IImmutableList _allPairs; + protected readonly IImmutableList _allPairs; protected readonly TagHandler _tagHandler; protected readonly UiSharedService _uiSharedService; private float _menuWidth = -1; - public int OnlinePairs => DrawPairs.Count(u => u.Pair.IsOnline); + public int OnlinePairs => DrawPairs.Count(u => u.DisplayEntry.Connection.IsOnline); public int TotalPairs => _allPairs.Count; private bool _wasHovered = false; + private bool _suppressNextRowToggle; + private bool _rowClickArmed; protected DrawFolderBase(string id, IImmutableList drawPairs, - IImmutableList allPairs, TagHandler tagHandler, UiSharedService uiSharedService) + IImmutableList allPairs, TagHandler tagHandler, UiSharedService uiSharedService) { _id = id; DrawPairs = drawPairs; @@ -31,11 +35,14 @@ public abstract class DrawFolderBase : IDrawFolder protected abstract bool RenderIfEmpty { get; } protected abstract bool RenderMenu { get; } + protected virtual bool EnableRowClick => true; public void Draw() { if (!RenderIfEmpty && !DrawPairs.Any()) return; + _suppressNextRowToggle = false; + using var id = ImRaii.PushId("folder_" + _id); var color = ImRaii.PushColor(ImGuiCol.ChildBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), _wasHovered); using (ImRaii.Child("folder__" + _id, new System.Numerics.Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) @@ -48,7 +55,8 @@ public abstract class DrawFolderBase : IDrawFolder _uiSharedService.IconText(icon); if (ImGui.IsItemClicked()) { - _tagHandler.SetTagOpen(_id, !_tagHandler.IsTagOpen(_id)); + ToggleFolderOpen(); + SuppressNextRowToggle(); } ImGui.SameLine(); @@ -62,10 +70,41 @@ public abstract class DrawFolderBase : IDrawFolder DrawName(rightSideStart - leftSideEnd); } - _wasHovered = ImGui.IsItemHovered(); + var rowHovered = ImGui.IsItemHovered(); + _wasHovered = rowHovered; + + if (EnableRowClick) + { + if (rowHovered && ImGui.IsMouseClicked(ImGuiMouseButton.Left) && !_suppressNextRowToggle) + { + _rowClickArmed = true; + } + + if (_rowClickArmed && rowHovered && ImGui.IsMouseReleased(ImGuiMouseButton.Left)) + { + ToggleFolderOpen(); + _rowClickArmed = false; + } + + if (!ImGui.IsMouseDown(ImGuiMouseButton.Left)) + { + _rowClickArmed = false; + } + } + else + { + _rowClickArmed = false; + } + + if (_wasHovered) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), spanFullWidth: true); + } color.Dispose(); + _suppressNextRowToggle = false; + ImGui.Separator(); // if opened draw content @@ -110,6 +149,7 @@ public abstract class DrawFolderBase : IDrawFolder ImGui.SameLine(windowEndX - barButtonSize.X); if (_uiSharedService.IconButton(FontAwesomeIcon.EllipsisV)) { + SuppressNextRowToggle(); ImGui.OpenPopup("User Flyout Menu"); } if (ImGui.BeginPopup("User Flyout Menu")) @@ -123,7 +163,16 @@ public abstract class DrawFolderBase : IDrawFolder _menuWidth = 0; } } - return DrawRightSide(rightSideStart); } + + protected void SuppressNextRowToggle() + { + _suppressNextRowToggle = true; + } + + private void ToggleFolderOpen() + { + _tagHandler.SetTagOpen(_id, !_tagHandler.IsTagOpen(_id)); + } } \ No newline at end of file diff --git a/LightlessSync/UI/Components/DrawFolderGroup.cs b/LightlessSync/UI/Components/DrawFolderGroup.cs index 6de9e28..ef9fdfb 100644 --- a/LightlessSync/UI/Components/DrawFolderGroup.cs +++ b/LightlessSync/UI/Components/DrawFolderGroup.cs @@ -5,9 +5,9 @@ using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.Group; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Models; using LightlessSync.WebAPI; using System.Collections.Immutable; @@ -22,7 +22,7 @@ public class DrawFolderGroup : DrawFolderBase private readonly SelectTagForSyncshellUi _selectTagForSyncshellUi; public DrawFolderGroup(string id, GroupFullInfoDto groupFullInfoDto, ApiController apiController, - IImmutableList drawPairs, IImmutableList allPairs, TagHandler tagHandler, IdDisplayHandler idDisplayHandler, + IImmutableList drawPairs, IImmutableList allPairs, TagHandler tagHandler, IdDisplayHandler idDisplayHandler, LightlessMediator lightlessMediator, UiSharedService uiSharedService, SelectTagForSyncshellUi selectTagForSyncshellUi) : base(id, drawPairs, allPairs, tagHandler, uiSharedService) { @@ -35,6 +35,7 @@ public class DrawFolderGroup : DrawFolderBase protected override bool RenderIfEmpty => true; protected override bool RenderMenu => true; + protected override bool EnableRowClick => false; private bool IsModerator => IsOwner || _groupFullInfoDto.GroupUserInfo.IsModerator(); private bool IsOwner => string.Equals(_groupFullInfoDto.OwnerUID, _apiController.UID, StringComparison.Ordinal); private bool IsPinned => _groupFullInfoDto.GroupUserInfo.IsPinned(); @@ -87,6 +88,13 @@ public class DrawFolderGroup : DrawFolderBase ImGui.Separator(); ImGui.TextUnformatted("General Syncshell Actions"); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.AddressCard, "Open Syncshell Profile", menuWidth, true)) + { + ImGui.CloseCurrentPopup(); + _lightlessMediator.Publish(new GroupProfileOpenStandaloneMessage(_groupFullInfoDto)); + } + UiSharedService.AttachToolTip("Opens the profile for this syncshell in a new window."); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Copy, "Copy ID", menuWidth, true)) { ImGui.CloseCurrentPopup(); @@ -160,6 +168,14 @@ public class DrawFolderGroup : DrawFolderBase { ImGui.Separator(); ImGui.TextUnformatted("Syncshell Admin Functions"); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserEdit, "Open Profile Editor", menuWidth, true)) + { + ImGui.CloseCurrentPopup(); + _lightlessMediator.Publish(new OpenGroupProfileEditorMessage(_groupFullInfoDto)); + } + UiSharedService.AttachToolTip("Open the syncshell profile editor."); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Cog, "Open Admin Panel", menuWidth, true)) { ImGui.CloseCurrentPopup(); @@ -244,6 +260,7 @@ public class DrawFolderGroup : DrawFolderBase ImGui.SameLine(); if (_uiSharedService.IconButton(pauseIcon)) { + SuppressNextRowToggle(); var perm = _groupFullInfoDto.GroupUserPermissions; perm.SetPaused(!perm.IsPaused()); _ = _apiController.GroupChangeIndividualPermissionState(new GroupPairUserPermissionDto(_groupFullInfoDto.Group, new(_apiController.UID), perm)); diff --git a/LightlessSync/UI/Components/DrawFolderTag.cs b/LightlessSync/UI/Components/DrawFolderTag.cs index 0c114e1..dcba0d4 100644 --- a/LightlessSync/UI/Components/DrawFolderTag.cs +++ b/LightlessSync/UI/Components/DrawFolderTag.cs @@ -1,11 +1,18 @@ -using Dalamud.Bindings.ImGui; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; +using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Extensions; -using LightlessSync.PlayerData.Pairs; +using LightlessSync.LightlessConfiguration; +using LightlessSync.Services.Mediator; +using LightlessSync.Services.ServerConfiguration; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Models; using LightlessSync.WebAPI; -using System.Collections.Immutable; namespace LightlessSync.UI.Components; @@ -14,14 +21,30 @@ public class DrawFolderTag : DrawFolderBase private readonly ApiController _apiController; private readonly SelectPairForTagUi _selectPairForTagUi; private readonly RenamePairTagUi _renameTagUi; + private readonly ServerConfigurationManager _serverConfigurationManager; + private readonly LightlessConfigService _configService; + private readonly LightlessMediator _mediator; - public DrawFolderTag(string id, IImmutableList drawPairs, IImmutableList allPairs, - TagHandler tagHandler, ApiController apiController, SelectPairForTagUi selectPairForTagUi, RenamePairTagUi renameTagUi, UiSharedService uiSharedService) + public DrawFolderTag( + string id, + IImmutableList drawPairs, + IImmutableList allPairs, + TagHandler tagHandler, + ApiController apiController, + SelectPairForTagUi selectPairForTagUi, + RenamePairTagUi renameTagUi, + UiSharedService uiSharedService, + ServerConfigurationManager serverConfigurationManager, + LightlessConfigService configService, + LightlessMediator mediator) : base(id, drawPairs, allPairs, tagHandler, uiSharedService) { _apiController = apiController; _selectPairForTagUi = selectPairForTagUi; _renameTagUi = renameTagUi; + _serverConfigurationManager = serverConfigurationManager; + _configService = configService; + _mediator = mediator; } protected override bool RenderIfEmpty => _id switch @@ -86,15 +109,18 @@ public class DrawFolderTag : DrawFolderBase if (RenderCount) { - using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, + ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemSpacing.X / 2f })) { ImGui.SameLine(); ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("[" + OnlinePairs.ToString() + "]"); + ImGui.TextUnformatted($"[{OnlinePairs}]"); } - UiSharedService.AttachToolTip(OnlinePairs + " online" + Environment.NewLine + TotalPairs + " total"); + + UiSharedService.AttachToolTip($"{OnlinePairs} online{Environment.NewLine}{TotalPairs} total"); } + ImGui.SameLine(); return ImGui.GetCursorPosX(); } @@ -102,19 +128,24 @@ public class DrawFolderTag : DrawFolderBase protected override void DrawMenu(float menuWidth) { ImGui.TextUnformatted("Group Menu"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Pairs", menuWidth, isInPopup: true)) + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Select Pairs", menuWidth, true)) { _selectPairForTagUi.Open(_id); } - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Pair Group", menuWidth, isInPopup: true)) + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Edit, "Rename Pair Group", menuWidth, true)) { _renameTagUi.Open(_id); } - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, isInPopup: true) && UiSharedService.CtrlPressed()) + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Pair Group", menuWidth, true) && + UiSharedService.CtrlPressed()) { _tagHandler.RemovePairTag(_id); } - UiSharedService.AttachToolTip("Hold CTRL to remove this Group permanently." + Environment.NewLine + + + UiSharedService.AttachToolTip( + "Hold CTRL to remove this Group permanently." + Environment.NewLine + "Note: this will not unpair with users in this Group."); } @@ -122,7 +153,7 @@ public class DrawFolderTag : DrawFolderBase { ImGui.AlignTextToFramePadding(); - string name = _id switch + var name = _id switch { TagHandler.CustomUnpairedTag => "One-sided Individual Pairs", TagHandler.CustomOnlineTag => "Online / Paused by you", @@ -138,16 +169,25 @@ public class DrawFolderTag : DrawFolderBase protected override float DrawRightSide(float currentRightSideX) { - if (!RenderPause) return currentRightSideX; - - var allArePaused = _allPairs.All(pair => pair.UserPair!.OwnPermissions.IsPaused()); - var pauseButton = allArePaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause; - var pauseButtonX = _uiSharedService.GetIconButtonSize(pauseButton).X; - - var buttonPauseOffset = currentRightSideX - pauseButtonX; - ImGui.SameLine(buttonPauseOffset); - if (_uiSharedService.IconButton(pauseButton)) + if (_id == TagHandler.CustomVisibleTag) { + return DrawVisibleFilter(currentRightSideX); + } + + if (!RenderPause) + { + return currentRightSideX; + } + + var allArePaused = _allPairs.All(entry => entry.SelfPermissions.IsPaused()); + var pauseIcon = allArePaused ? FontAwesomeIcon.Play : FontAwesomeIcon.Pause; + var pauseButtonSize = _uiSharedService.GetIconButtonSize(pauseIcon); + + var buttonPauseOffset = currentRightSideX - pauseButtonSize.X; + ImGui.SameLine(buttonPauseOffset); + if (_uiSharedService.IconButton(pauseIcon)) + { + SuppressNextRowToggle(); if (allArePaused) { ResumeAllPairs(_allPairs); @@ -157,39 +197,89 @@ public class DrawFolderTag : DrawFolderBase PauseRemainingPairs(_allPairs); } } - if (allArePaused) - { - UiSharedService.AttachToolTip($"Resume pairing with all pairs in {_id}"); - } - else - { - UiSharedService.AttachToolTip($"Pause pairing with all pairs in {_id}"); - } + + UiSharedService.AttachToolTip(allArePaused + ? $"Resume pairing with all pairs in {_id}" + : $"Pause pairing with all pairs in {_id}"); return currentRightSideX; } - private void PauseRemainingPairs(IEnumerable availablePairs) + private void PauseRemainingPairs(IEnumerable entries) { - _ = _apiController.SetBulkPermissions(new(availablePairs - .ToDictionary(g => g.UserData.UID, g => - { - var perm = g.UserPair.OwnPermissions; - perm.SetPaused(paused: true); - return perm; - }, StringComparer.Ordinal), new(StringComparer.Ordinal))) + _ = _apiController.SetBulkPermissions(new( + entries.ToDictionary(entry => entry.DisplayEntry.User.UID, entry => + { + var permissions = entry.SelfPermissions; + permissions.SetPaused(true); + return permissions; + }, StringComparer.Ordinal), + new(StringComparer.Ordinal))) .ConfigureAwait(false); } - private void ResumeAllPairs(IEnumerable availablePairs) + private void ResumeAllPairs(IEnumerable entries) { - _ = _apiController.SetBulkPermissions(new(availablePairs - .ToDictionary(g => g.UserData.UID, g => - { - var perm = g.UserPair.OwnPermissions; - perm.SetPaused(paused: false); - return perm; - }, StringComparer.Ordinal), new(StringComparer.Ordinal))) + _ = _apiController.SetBulkPermissions(new( + entries.ToDictionary(entry => entry.DisplayEntry.User.UID, entry => + { + var permissions = entry.SelfPermissions; + permissions.SetPaused(false); + return permissions; + }, StringComparer.Ordinal), + new(StringComparer.Ordinal))) .ConfigureAwait(false); } + + private float DrawVisibleFilter(float currentRightSideX) + { + var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Filter); + var spacingX = ImGui.GetStyle().ItemSpacing.X; + var buttonStart = currentRightSideX - buttonSize.X; + + ImGui.SameLine(buttonStart); + if (_uiSharedService.IconButton(FontAwesomeIcon.Filter)) + { + SuppressNextRowToggle(); + ImGui.OpenPopup($"visible-filter-{_id}"); + } + + UiSharedService.AttachToolTip("Adjust how visible pairs are ordered."); + + if (ImGui.BeginPopup($"visible-filter-{_id}")) + { + ImGui.TextUnformatted("Visible Pair Ordering"); + ImGui.Separator(); + + foreach (VisiblePairSortMode mode in Enum.GetValues()) + { + var selected = _configService.Current.VisiblePairSortMode == mode; + if (ImGui.MenuItem(GetSortLabel(mode), string.Empty, selected)) + { + if (!selected) + { + _configService.Current.VisiblePairSortMode = mode; + _configService.Save(); + _mediator.Publish(new RefreshUiMessage()); + } + + ImGui.CloseCurrentPopup(); + } + } + + ImGui.EndPopup(); + } + + return buttonStart - spacingX; + } + + private static string GetSortLabel(VisiblePairSortMode mode) => mode switch + { + VisiblePairSortMode.Alphabetical => "Alphabetical", + VisiblePairSortMode.VramUsage => "VRAM usage (descending)", + VisiblePairSortMode.EffectiveVramUsage => "Effective VRAM usage (descending)", + VisiblePairSortMode.TriangleCount => "Triangle count (descending)", + VisiblePairSortMode.PreferredDirectPairs => "Preferred permissions & Direct pairs", + _ => "Default", + }; } \ No newline at end of file diff --git a/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs b/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs index 1bb3d79..72063f2 100644 --- a/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs +++ b/LightlessSync/UI/Components/DrawGroupedGroupFolder.cs @@ -1,9 +1,11 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; +using LightlessSync.UI; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.Group; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Style; using LightlessSync.UI.Models; using LightlessSync.WebAPI; using System.Collections.Immutable; @@ -22,6 +24,7 @@ public class DrawGroupedGroupFolder : IDrawFolder private readonly RenameSyncshellTagUi _renameSyncshellTagUi; private bool _wasHovered = false; private float _menuWidth; + private bool _rowClickArmed; public IImmutableList DrawPairs => _groups.SelectMany(g => g.GroupDrawFolder.DrawPairs).ToImmutableList(); public int OnlinePairs => _groups.SelectMany(g => g.GroupDrawFolder.DrawPairs).Where(g => g.Pair.IsOnline).DistinctBy(g => g.Pair.UserData.UID).Count(); @@ -48,7 +51,9 @@ public class DrawGroupedGroupFolder : IDrawFolder using var id = ImRaii.PushId(_id); var color = ImRaii.PushColor(ImGuiCol.ChildBg, ImGui.GetColorU32(ImGuiCol.FrameBgHovered), _wasHovered); - using (ImRaii.Child("folder__" + _id, new Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) + var allowRowClick = string.IsNullOrEmpty(_tag); + var suppressRowToggle = false; + using (ImRaii.Child("folder__" + _id, new System.Numerics.Vector2(UiSharedService.GetWindowContentRegionWidth() - ImGui.GetCursorPosX(), ImGui.GetFrameHeight()))) { ImGui.Dummy(new Vector2(0f, ImGui.GetFrameHeight())); using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(0f, 0f))) @@ -61,6 +66,7 @@ public class DrawGroupedGroupFolder : IDrawFolder if (ImGui.IsItemClicked()) { _tagHandler.SetTagOpen(_id, !_tagHandler.IsTagOpen(_id)); + suppressRowToggle = true; } ImGui.SameLine(); @@ -92,7 +98,7 @@ public class DrawGroupedGroupFolder : IDrawFolder ImGui.SameLine(); DrawPauseButton(); ImGui.SameLine(); - DrawMenu(); + DrawMenu(ref suppressRowToggle); } else { ImGui.TextUnformatted("All Syncshells"); @@ -102,7 +108,36 @@ public class DrawGroupedGroupFolder : IDrawFolder } } color.Dispose(); - _wasHovered = ImGui.IsItemHovered(); + var rowHovered = ImGui.IsItemHovered(); + _wasHovered = rowHovered; + + if (allowRowClick) + { + if (rowHovered && ImGui.IsMouseClicked(ImGuiMouseButton.Left) && !suppressRowToggle) + { + _rowClickArmed = true; + } + + if (_rowClickArmed && rowHovered && ImGui.IsMouseReleased(ImGuiMouseButton.Left)) + { + _tagHandler.SetTagOpen(_id, !_tagHandler.IsTagOpen(_id)); + _rowClickArmed = false; + } + + if (!ImGui.IsMouseDown(ImGuiMouseButton.Left)) + { + _rowClickArmed = false; + } + } + else + { + _rowClickArmed = false; + } + + if (_wasHovered) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), spanFullWidth: true); + } ImGui.Separator(); @@ -154,7 +189,7 @@ public class DrawGroupedGroupFolder : IDrawFolder } } - protected void DrawMenu() + protected void DrawMenu(ref bool suppressRowToggle) { var barButtonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.EllipsisV); var windowEndX = ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth(); @@ -162,6 +197,7 @@ public class DrawGroupedGroupFolder : IDrawFolder ImGui.SameLine(windowEndX - barButtonSize.X); if (_uiSharedService.IconButton(FontAwesomeIcon.EllipsisV)) { + suppressRowToggle = true; ImGui.OpenPopup("User Flyout Menu"); } if (ImGui.BeginPopup("User Flyout Menu")) diff --git a/LightlessSync/UI/Components/DrawUserPair.cs b/LightlessSync/UI/Components/DrawUserPair.cs index 4c4c1d4..0c8b649 100644 --- a/LightlessSync/UI/Components/DrawUserPair.cs +++ b/LightlessSync/UI/Components/DrawUserPair.cs @@ -12,11 +12,16 @@ using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Models; +using LightlessSync.UI.Style; using LightlessSync.Utils; using LightlessSync.WebAPI; +using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; using System.Text; +using LightlessSync.UI; namespace LightlessSync.UI.Components; @@ -27,29 +32,41 @@ public class DrawUserPair protected readonly LightlessMediator _mediator; protected readonly List _syncedGroups; private readonly GroupFullInfoDto? _currentGroup; - protected Pair _pair; + protected Pair? _pair; + private PairUiEntry _uiEntry; + protected PairDisplayEntry _displayEntry; private readonly string _id; private readonly SelectTagForPairUi _selectTagForPairUi; private readonly ServerConfigurationManager _serverConfigurationManager; private readonly UiSharedService _uiSharedService; private readonly PlayerPerformanceConfigService _performanceConfigService; private readonly CharaDataManager _charaDataManager; + private readonly PairLedger _pairLedger; private float _menuWidth = -1; private bool _wasHovered = false; private TooltipSnapshot _tooltipSnapshot = TooltipSnapshot.Empty; private string _cachedTooltip = string.Empty; - public DrawUserPair(string id, Pair entry, List syncedGroups, + public DrawUserPair( + string id, + PairUiEntry uiEntry, + Pair? legacyPair, GroupFullInfoDto? currentGroup, - ApiController apiController, IdDisplayHandler uIDDisplayHandler, - LightlessMediator lightlessMediator, SelectTagForPairUi selectTagForPairUi, + ApiController apiController, + IdDisplayHandler uIDDisplayHandler, + LightlessMediator lightlessMediator, + SelectTagForPairUi selectTagForPairUi, ServerConfigurationManager serverConfigurationManager, - UiSharedService uiSharedService, PlayerPerformanceConfigService performanceConfigService, - CharaDataManager charaDataManager) + UiSharedService uiSharedService, + PlayerPerformanceConfigService performanceConfigService, + CharaDataManager charaDataManager, + PairLedger pairLedger) { _id = id; - _pair = entry; - _syncedGroups = syncedGroups; + _uiEntry = uiEntry; + _displayEntry = uiEntry.DisplayEntry; + _pair = legacyPair ?? throw new ArgumentNullException(nameof(legacyPair)); + _syncedGroups = uiEntry.DisplayEntry.Groups.ToList(); _currentGroup = currentGroup; _apiController = apiController; _displayHandler = uIDDisplayHandler; @@ -59,6 +76,18 @@ public class DrawUserPair _uiSharedService = uiSharedService; _performanceConfigService = performanceConfigService; _charaDataManager = charaDataManager; + _pairLedger = pairLedger; + } + + public PairDisplayEntry DisplayEntry => _displayEntry; + public PairUiEntry UiEntry => _uiEntry; + + public void UpdateDisplayEntry(PairUiEntry entry) + { + _uiEntry = entry; + _displayEntry = entry.DisplayEntry; + _syncedGroups.Clear(); + _syncedGroups.AddRange(entry.DisplayEntry.Groups); } public Pair Pair => _pair; @@ -77,6 +106,10 @@ public class DrawUserPair DrawName(posX, rightSide); } _wasHovered = ImGui.IsItemHovered(); + if (_wasHovered) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), spanFullWidth: true); + } color.Dispose(); } @@ -103,7 +136,7 @@ public class DrawUserPair if (_uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Cycle pause state", _menuWidth, true)) { - _ = _apiController.CyclePauseAsync(_pair.UserData); + _ = _apiController.CyclePauseAsync(_pair); ImGui.CloseCurrentPopup(); } ImGui.Separator(); @@ -313,6 +346,7 @@ public class DrawUserPair _pair.PlayerName ?? string.Empty, _pair.LastAppliedDataBytes, _pair.LastAppliedApproximateVRAMBytes, + _pair.LastAppliedApproximateEffectiveVRAMBytes, _pair.LastAppliedDataTris, _pair.IsPaired, groupDisplays is null ? ImmutableArray.Empty : ImmutableArray.CreateRange(groupDisplays)); @@ -381,7 +415,14 @@ public class DrawUserPair { builder.Append(Environment.NewLine); builder.Append("Approx. VRAM Usage: "); - builder.Append(UiSharedService.ByteToString(snapshot.LastAppliedApproximateVRAMBytes, true)); + var originalText = UiSharedService.ByteToString(snapshot.LastAppliedApproximateVRAMBytes, true); + builder.Append(originalText); + if (snapshot.LastAppliedApproximateEffectiveVRAMBytes >= 0) + { + builder.Append(" (Effective: "); + builder.Append(UiSharedService.ByteToString(snapshot.LastAppliedApproximateEffectiveVRAMBytes, true)); + builder.Append(')'); + } } if (snapshot.LastAppliedDataTris >= 0) @@ -420,12 +461,13 @@ public class DrawUserPair string PlayerName, long LastAppliedDataBytes, long LastAppliedApproximateVRAMBytes, + long LastAppliedApproximateEffectiveVRAMBytes, long LastAppliedDataTris, bool IsPaired, ImmutableArray GroupDisplays) { public static TooltipSnapshot Empty { get; } = - new(false, false, false, IndividualPairStatus.None, string.Empty, string.Empty, -1, -1, -1, false, ImmutableArray.Empty); + new(false, false, false, IndividualPairStatus.None, string.Empty, string.Empty, -1, -1, -1, -1, false, ImmutableArray.Empty); } private void DrawPairedClientMenu() @@ -647,7 +689,13 @@ public class DrawUserPair private void DrawSyncshellMenu(GroupFullInfoDto group, bool selfIsOwner, bool selfIsModerator, bool userIsPinned, bool userIsModerator) { - if (selfIsOwner || ((selfIsModerator) && (!userIsModerator))) + var showModeratorActions = selfIsOwner || (selfIsModerator && !userIsModerator); + var showOwnerActions = selfIsOwner; + + if (showModeratorActions || showOwnerActions) + ImGui.Separator(); + + if (showModeratorActions) { ImGui.TextUnformatted("Syncshell Moderator Functions"); var pinText = userIsPinned ? "Unpin user" : "Pin user"; @@ -683,7 +731,7 @@ public class DrawUserPair ImGui.Separator(); } - if (selfIsOwner) + if (showOwnerActions) { ImGui.TextUnformatted("Syncshell Owner Functions"); string modText = userIsModerator ? "Demod user" : "Mod user"; diff --git a/LightlessSync/UI/Components/Popup/BanUserPopupHandler.cs b/LightlessSync/UI/Components/Popup/BanUserPopupHandler.cs index b1cb3f8..ee80074 100644 --- a/LightlessSync/UI/Components/Popup/BanUserPopupHandler.cs +++ b/LightlessSync/UI/Components/Popup/BanUserPopupHandler.cs @@ -1,6 +1,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using LightlessSync.API.Dto.Group; +using LightlessSync.PlayerData.Factories; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.WebAPI; @@ -12,14 +13,16 @@ public class BanUserPopupHandler : IPopupHandler { private readonly ApiController _apiController; private readonly UiSharedService _uiSharedService; + private readonly PairFactory _pairFactory; private string _banReason = string.Empty; private GroupFullInfoDto _group = null!; private Pair _reportedPair = null!; - public BanUserPopupHandler(ApiController apiController, UiSharedService uiSharedService) + public BanUserPopupHandler(ApiController apiController, UiSharedService uiSharedService, PairFactory pairFactory) { _apiController = apiController; _uiSharedService = uiSharedService; + _pairFactory = pairFactory; } public Vector2 PopupSize => new(500, 250); @@ -43,7 +46,7 @@ public class BanUserPopupHandler : IPopupHandler public void Open(OpenBanUserPopupMessage message) { - _reportedPair = message.PairToBan; + _reportedPair = _pairFactory.Create(message.PairToBan.UniqueIdent) ?? message.PairToBan; _group = message.GroupFullInfoDto; _banReason = string.Empty; } diff --git a/LightlessSync/UI/Components/SelectPairForTagUi.cs b/LightlessSync/UI/Components/SelectPairForTagUi.cs index 89db40e..a2ae7d1 100644 --- a/LightlessSync/UI/Components/SelectPairForTagUi.cs +++ b/LightlessSync/UI/Components/SelectPairForTagUi.cs @@ -23,7 +23,7 @@ public class SelectPairForTagUi _uidDisplayHandler = uidDisplayHandler; } - public void Draw(List pairs) + public void Draw(IReadOnlyList pairs) { var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale; var minSize = new Vector2(300, workHeight < 400 ? workHeight : 400) * ImGuiHelpers.GlobalScale; diff --git a/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs b/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs index 62dd1d6..63e48e0 100644 --- a/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs +++ b/LightlessSync/UI/Components/SelectSyncshellForTagUi.cs @@ -21,7 +21,7 @@ public class SelectSyncshellForTagUi _tagHandler = tagHandler; } - public void Draw(List groups) + public void Draw(IReadOnlyCollection groups) { var workHeight = ImGui.GetMainViewport().WorkSize.Y / ImGuiHelpers.GlobalScale; var minSize = new Vector2(300, workHeight < 400 ? workHeight : 400) * ImGuiHelpers.GlobalScale; diff --git a/LightlessSync/UI/DataAnalysisUi.cs b/LightlessSync/UI/DataAnalysisUi.cs index 5b750f3..725e004 100644 --- a/LightlessSync/UI/DataAnalysisUi.cs +++ b/LightlessSync/UI/DataAnalysisUi.cs @@ -1,6 +1,7 @@ using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Colors; +using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using LightlessSync.API.Data.Enum; @@ -9,41 +10,94 @@ using LightlessSync.Interop.Ipc; using LightlessSync.LightlessConfiguration; using LightlessSync.Services; using LightlessSync.Services.Mediator; +using LightlessSync.Services.TextureCompression; using LightlessSync.Utils; +using Penumbra.Api.Enums; using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; using System.Numerics; +using System.Threading; +using System.Threading.Tasks; namespace LightlessSync.UI; public class DataAnalysisUi : WindowMediatorSubscriberBase { + private const float MinTextureFilterPaneWidth = 305f; + private const float MaxTextureFilterPaneWidth = 405f; + private const float MinTextureDetailPaneWidth = 580f; + private const float MaxTextureDetailPaneWidth = 720f; + private const float SelectedFilePanelLogicalHeight = 90f; + private static readonly Vector4 SelectedTextureRowTextColor = new(0f, 0f, 0f, 1f); + private readonly CharacterAnalyzer _characterAnalyzer; - private readonly Progress<(string, int)> _conversionProgress = new(); + private readonly Progress _conversionProgress = new(); private readonly IpcManager _ipcManager; private readonly UiSharedService _uiSharedService; private readonly PlayerPerformanceConfigService _playerPerformanceConfig; private readonly TransientResourceManager _transientResourceManager; private readonly TransientConfigService _transientConfigService; - private readonly Dictionary _texturesToConvert = new(StringComparer.Ordinal); + private readonly TextureCompressionService _textureCompressionService; + private readonly TextureMetadataHelper _textureMetadataHelper; + + private readonly List _textureRows = new(); + private readonly Dictionary _textureSelections = new(StringComparer.OrdinalIgnoreCase); + private readonly HashSet _selectedTextureKeys = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _texturePreviews = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _textureWorkspaceTabs = new(); + private readonly List _storedPathsToRemove = []; + private readonly Dictionary _filePathResolve = []; + private Dictionary>? _cachedAnalysis; private CancellationTokenSource _conversionCancellationTokenSource = new(); - private string _conversionCurrentFileName = string.Empty; - private int _conversionCurrentFileProgress = 0; + private CancellationTokenSource _transientRecordCts = new(); + private Task? _conversionTask; - private bool _enableBc7ConversionMode = false; - private bool _hasUpdate = false; - private bool _modalOpen = false; + private TextureConversionProgress? _lastConversionProgress; + + private float _textureFilterPaneWidth = 320f; + private float _textureDetailPaneWidth = 360f; + private float _textureDetailHeight = 360f; + private float _texturePreviewSize = 360f; + + private string _conversionCurrentFileName = string.Empty; private string _selectedFileTypeTab = string.Empty; private string _selectedHash = string.Empty; - private ObjectKind _selectedObjectTab; + private string _textureSearch = string.Empty; + private string _textureSlotFilter = "All"; + private string _selectedTextureKey = string.Empty; + private string _selectedStoredCharacter = string.Empty; + private string _selectedJobEntry = string.Empty; + private string _filterGamePath = string.Empty; + private string _filterFilePath = string.Empty; + + private int _conversionCurrentFileProgress = 0; + private int _conversionTotalJobs; + + private bool _hasUpdate = false; + private bool _modalOpen = false; private bool _showModal = false; - private CancellationTokenSource _transientRecordCts = new(); + private bool _textureRowsDirty = true; + private bool _conversionFailed; + private bool _showAlreadyAddedTransients = false; + private bool _acknowledgeReview = false; + + private ObjectKind _selectedObjectTab; + + private TextureUsageCategory? _textureCategoryFilter = null; + private TextureMapKind? _textureMapFilter = null; + private TextureCompressionTarget? _textureTargetFilter = null; public DataAnalysisUi(ILogger logger, LightlessMediator mediator, CharacterAnalyzer characterAnalyzer, IpcManager ipcManager, PerformanceCollectorService performanceCollectorService, UiSharedService uiSharedService, PlayerPerformanceConfigService playerPerformanceConfig, TransientResourceManager transientResourceManager, - TransientConfigService transientConfigService) + TransientConfigService transientConfigService, TextureCompressionService textureCompressionService, + TextureMetadataHelper textureMetadataHelper) : base(logger, mediator, "Lightless Character Data Analysis", performanceCollectorService) { _characterAnalyzer = characterAnalyzer; @@ -52,6 +106,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase _playerPerformanceConfig = playerPerformanceConfig; _transientResourceManager = transientResourceManager; _transientConfigService = transientConfigService; + _textureCompressionService = textureCompressionService; + _textureMetadataHelper = textureMetadataHelper; Mediator.Subscribe(this, (_) => { _hasUpdate = true; @@ -60,8 +116,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase { MinimumSize = new() { - X = 800, - Y = 600 + X = 1650, + Y = 1000 }, MaximumSize = new() { @@ -75,91 +131,139 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase protected override void DrawInternal() { - if (_conversionTask != null && !_conversionTask.IsCompleted) + HandleConversionModal(); + RefreshAnalysisCache(); + DrawContentTabs(); + } + + private void HandleConversionModal() + { + if (_conversionTask == null) { - _showModal = true; - if (ImGui.BeginPopupModal("BC7 Conversion in Progress")) - { - ImGui.TextUnformatted("BC7 Conversion in progress: " + _conversionCurrentFileProgress + "/" + _texturesToConvert.Count); - UiSharedService.TextWrapped("Current file: " + _conversionCurrentFileName); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion")) - { - _conversionCancellationTokenSource.Cancel(); - } - UiSharedService.SetScaledWindowSize(500); - ImGui.EndPopup(); - } - else - { - _modalOpen = false; - } + return; } - else if (_conversionTask != null && _conversionTask.IsCompleted && _texturesToConvert.Count > 0) + + if (_conversionTask.IsCompleted) + { + ResetConversionModalState(); + return; + } + + _showModal = true; + if (ImGui.BeginPopupModal("Texture Compression in Progress", ImGuiWindowFlags.AlwaysAutoResize)) + { + DrawConversionModalContent(); + ImGui.EndPopup(); + } + else { - _conversionTask = null; - _texturesToConvert.Clear(); - _showModal = false; _modalOpen = false; - _enableBc7ConversionMode = false; } if (_showModal && !_modalOpen) { - ImGui.OpenPopup("BC7 Conversion in Progress"); + ImGui.OpenPopup("Texture Compression in Progress"); _modalOpen = true; } - - if (_hasUpdate) - { - _cachedAnalysis = _characterAnalyzer.LastAnalysis.DeepClone(); - _hasUpdate = false; - } - - using var tabBar = ImRaii.TabBar("analysisRecordingTabBar"); - using (var tabItem = ImRaii.TabItem("Analysis")) - { - if (tabItem) - { - using var id = ImRaii.PushId("analysis"); - DrawAnalysis(); - } - } - using (var tabItem = ImRaii.TabItem("Transient Files")) - { - if (tabItem) - { - using var tabbar = ImRaii.TabBar("transientData"); - - using (var transientData = ImRaii.TabItem("Stored Transient File Data")) - { - using var id = ImRaii.PushId("data"); - - if (transientData) - { - DrawStoredData(); - } - } - using (var transientRecord = ImRaii.TabItem("Record Transient Data")) - { - using var id = ImRaii.PushId("recording"); - - if (transientRecord) - { - DrawRecording(); - } - } - } - } } - private bool _showAlreadyAddedTransients = false; - private bool _acknowledgeReview = false; - private string _selectedStoredCharacter = string.Empty; - private string _selectedJobEntry = string.Empty; - private readonly List _storedPathsToRemove = []; - private readonly Dictionary _filePathResolve = []; - private string _filterGamePath = string.Empty; - private string _filterFilePath = string.Empty; + private void DrawConversionModalContent() + { + var progress = _lastConversionProgress; + var total = progress?.Total ?? Math.Max(_conversionTotalJobs, 1); + var completed = progress != null + ? Math.Min(progress.Completed + 1, total) + : _conversionCurrentFileProgress; + var currentLabel = !string.IsNullOrEmpty(_conversionCurrentFileName) + ? _conversionCurrentFileName + : "Preparing..."; + + ImGui.TextUnformatted($"Compressing textures ({completed}/{total})"); + UiSharedService.TextWrapped("Current file: " + currentLabel); + + if (_conversionFailed) + { + UiSharedService.ColorText("Conversion encountered errors. Please review the log for details.", ImGuiColors.DalamudRed); + } + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.StopCircle, "Cancel conversion")) + { + _conversionCancellationTokenSource.Cancel(); + } + + UiSharedService.SetScaledWindowSize(520); + } + + private void ResetConversionModalState() + { + _conversionTask = null; + _showModal = false; + _modalOpen = false; + _lastConversionProgress = null; + _conversionCurrentFileName = string.Empty; + _conversionCurrentFileProgress = 0; + _conversionTotalJobs = 0; + } + + private void RefreshAnalysisCache() + { + if (!_hasUpdate) + { + return; + } + + _cachedAnalysis = _characterAnalyzer.LastAnalysis.DeepClone(); + _hasUpdate = false; + _textureRowsDirty = true; + } + + private void DrawContentTabs() + { + using var tabBar = ImRaii.TabBar("analysisRecordingTabBar"); + DrawAnalysisTab(); + DrawTransientFilesTab(); + } + + private void DrawAnalysisTab() + { + using var tabItem = ImRaii.TabItem("Analysis"); + if (!tabItem) + { + return; + } + + using var id = ImRaii.PushId("analysis"); + DrawAnalysis(); + } + + private void DrawTransientFilesTab() + { + using var tabItem = ImRaii.TabItem("Transient Files"); + if (!tabItem) + { + return; + } + + using var tabbar = ImRaii.TabBar("transientData"); + + using (var transientData = ImRaii.TabItem("Stored Transient File Data")) + { + using var id = ImRaii.PushId("data"); + if (transientData) + { + DrawStoredData(); + } + } + + using (var transientRecord = ImRaii.TabItem("Record Transient Data")) + { + using var id = ImRaii.PushId("recording"); + if (transientRecord) + { + DrawRecording(); + } + } + } private void DrawStoredData() { @@ -176,191 +280,258 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase var config = _transientConfigService.Current.TransientConfigs; Vector2 availableContentRegion = Vector2.Zero; - using (ImRaii.Group()) + DrawCharacterColumn(); + + ImGui.SameLine(); + + bool selectedData = config.TryGetValue(_selectedStoredCharacter, out var transientStorage) && transientStorage != null; + DrawJobColumn(); + + ImGui.SameLine(); + DrawAttachedFilesColumn(); + + return; + + void DrawCharacterColumn() { - ImGui.TextUnformatted("Character"); - ImGui.Separator(); - ImGuiHelpers.ScaledDummy(3); - availableContentRegion = ImGui.GetContentRegionAvail(); - using (ImRaii.ListBox("##characters", new Vector2(200, availableContentRegion.Y))) + using (ImRaii.Group()) { - foreach (var entry in config) + ImGui.TextUnformatted("Character"); + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(3); + availableContentRegion = ImGui.GetContentRegionAvail(); + using (ImRaii.ListBox("##characters", new Vector2(200, availableContentRegion.Y))) { - var name = entry.Key.Split("_"); - if (!_uiSharedService.WorldData.TryGetValue(ushort.Parse(name[1]), out var worldname)) + foreach (var entry in config) { - continue; - } - if (ImGui.Selectable(name[0] + " (" + worldname + ")", string.Equals(_selectedStoredCharacter, entry.Key, StringComparison.Ordinal))) - { - _selectedStoredCharacter = entry.Key; - _selectedJobEntry = string.Empty; - _storedPathsToRemove.Clear(); - _filePathResolve.Clear(); - _filterFilePath = string.Empty; - _filterGamePath = string.Empty; + var name = entry.Key.Split("_"); + if (!_uiSharedService.WorldData.TryGetValue(ushort.Parse(name[1]), out var worldname)) + { + continue; + } + + bool isSelected = string.Equals(_selectedStoredCharacter, entry.Key, StringComparison.Ordinal); + if (ImGui.Selectable(name[0] + " (" + worldname + ")", isSelected)) + { + _selectedStoredCharacter = entry.Key; + _selectedJobEntry = string.Empty; + ResetSelectionFilters(); + } } } } } - ImGui.SameLine(); - bool selectedData = config.TryGetValue(_selectedStoredCharacter, out var transientStorage) && transientStorage != null; - using (ImRaii.Group()) + + void DrawJobColumn() { - ImGui.TextUnformatted("Job"); - ImGui.Separator(); - ImGuiHelpers.ScaledDummy(3); - using (ImRaii.ListBox("##data", new Vector2(150, availableContentRegion.Y))) + using (ImRaii.Group()) { - if (selectedData) + ImGui.TextUnformatted("Job"); + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(3); + using (ImRaii.ListBox("##data", new Vector2(150, availableContentRegion.Y))) { + if (!selectedData) + { + return; + } + if (ImGui.Selectable("All Jobs", string.Equals(_selectedJobEntry, "alljobs", StringComparison.Ordinal))) { _selectedJobEntry = "alljobs"; } + foreach (var job in transientStorage!.JobSpecificCache) { - if (!_uiSharedService.JobData.TryGetValue(job.Key, out var jobName)) continue; + if (!_uiSharedService.JobData.TryGetValue(job.Key, out var jobName)) + { + continue; + } + if (ImGui.Selectable(jobName, string.Equals(_selectedJobEntry, job.Key.ToString(), StringComparison.Ordinal))) { _selectedJobEntry = job.Key.ToString(); + ResetSelectionFilters(); + } + } + } + } + } + + void DrawAttachedFilesColumn() + { + using (ImRaii.Group()) + { + var selectedList = string.Equals(_selectedJobEntry, "alljobs", StringComparison.Ordinal) + ? config[_selectedStoredCharacter].GlobalPersistentCache + : (string.IsNullOrEmpty(_selectedJobEntry) ? [] : config[_selectedStoredCharacter].JobSpecificCache[uint.Parse(_selectedJobEntry)]); + ImGui.TextUnformatted($"Attached Files (Total Files: {selectedList.Count})"); + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(3); + using (ImRaii.Disabled(string.IsNullOrEmpty(_selectedJobEntry))) + { + var restContent = availableContentRegion.X - ImGui.GetCursorPosX(); + using var group = ImRaii.Group(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowRight, "Resolve Game Paths to used File Paths")) + { + _ = Task.Run(async () => + { + if (!_ipcManager.Penumbra.APIAvailable) + { + return; + } + + var paths = selectedList.ToArray(); + var (forward, _) = await _ipcManager.Penumbra.ResolvePathsAsync(paths, Array.Empty()).ConfigureAwait(false); + for (int i = 0; i < paths.Length && i < forward.Length; i++) + { + var result = forward[i]; + if (string.IsNullOrEmpty(result)) + { + continue; + } + + if (!_filePathResolve.TryAdd(paths[i], result)) + { + _filePathResolve[paths[i]] = result; + } + } + }); + } + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Eraser, "Clear Game Path File Resolves")) + { + _filePathResolve.Clear(); + } + ImGui.SameLine(); + using (ImRaii.Disabled(!_storedPathsToRemove.Any())) + { + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Delete Selected Game Paths")) + { + foreach (var entry in _storedPathsToRemove) + { + config[_selectedStoredCharacter].GlobalPersistentCache.Remove(entry); + foreach (var job in config[_selectedStoredCharacter].JobSpecificCache) + { + job.Value.Remove(entry); + } + } + _storedPathsToRemove.Clear(); - _filePathResolve.Clear(); + _transientConfigService.Save(); + _transientResourceManager.RebuildSemiTransientResources(); _filterFilePath = string.Empty; _filterGamePath = string.Empty; } } + ImGui.SameLine(); + using (ImRaii.Disabled(!UiSharedService.CtrlPressed())) + { + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear ALL Game Paths")) + { + selectedList.Clear(); + _transientConfigService.Save(); + _transientResourceManager.RebuildSemiTransientResources(); + _filterFilePath = string.Empty; + _filterGamePath = string.Empty; + } + } + UiSharedService.AttachToolTip("Hold CTRL to delete all game paths from the displayed list" + + UiSharedService.TooltipSeparator + "You usually do not need to do this. All animation and VFX data will be automatically handled through Lightless."); + ImGuiHelpers.ScaledDummy(5); + ImGuiHelpers.ScaledDummy(30); + ImGui.SameLine(); + ImGui.SetNextItemWidth((restContent - 30) / 2f); + ImGui.InputTextWithHint("##filterGamePath", "Filter by Game Path", ref _filterGamePath, 255); + ImGui.SameLine(); + ImGui.SetNextItemWidth((restContent - 30) / 2f); + ImGui.InputTextWithHint("##filterFilePath", "Filter by File Path", ref _filterFilePath, 255); + + using (var dataTable = ImRaii.Table("##table", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg)) + { + if (dataTable) + { + ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 30); + ImGui.TableSetupColumn("Game Path", ImGuiTableColumnFlags.WidthFixed, (restContent - 30) / 2f); + ImGui.TableSetupColumn("File Path", ImGuiTableColumnFlags.WidthFixed, (restContent - 30) / 2f); + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); + int id = 0; + foreach (var entry in selectedList) + { + if (!string.IsNullOrWhiteSpace(_filterGamePath) && !entry.Contains(_filterGamePath, StringComparison.OrdinalIgnoreCase)) + continue; + bool hasFileResolve = _filePathResolve.TryGetValue(entry, out var filePath); + + if (hasFileResolve && !string.IsNullOrEmpty(_filterFilePath) && !filePath!.Contains(_filterFilePath, StringComparison.OrdinalIgnoreCase)) + continue; + + using var imguiid = ImRaii.PushId(id++); + ImGui.TableNextColumn(); + bool isSelected = _storedPathsToRemove.Contains(entry, StringComparer.Ordinal); + if (ImGui.Checkbox("##", ref isSelected)) + { + if (isSelected) + _storedPathsToRemove.Add(entry); + else + _storedPathsToRemove.Remove(entry); + } + ImGui.TableNextColumn(); + ImGui.TextUnformatted(entry); + UiSharedService.AttachToolTip(entry + UiSharedService.TooltipSeparator + "Click to copy to clipboard"); + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) + { + ImGui.SetClipboardText(entry); + } + ImGui.TableNextColumn(); + if (hasFileResolve) + { + ImGui.TextUnformatted(filePath ?? "Unk"); + UiSharedService.AttachToolTip(filePath ?? "Unk" + UiSharedService.TooltipSeparator + "Click to copy to clipboard"); + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) + { + ImGui.SetClipboardText(filePath); + } + } + else + { + ImGui.TextUnformatted("-"); + UiSharedService.AttachToolTip("Resolve Game Paths to used File Paths to display the associated file paths."); + } + } + } + } } } } - ImGui.SameLine(); - using (ImRaii.Group()) + + void ResetSelectionFilters() { - var selectedList = string.Equals(_selectedJobEntry, "alljobs", StringComparison.Ordinal) - ? config[_selectedStoredCharacter].GlobalPersistentCache - : (string.IsNullOrEmpty(_selectedJobEntry) ? [] : config[_selectedStoredCharacter].JobSpecificCache[uint.Parse(_selectedJobEntry)]); - ImGui.TextUnformatted($"Attached Files (Total Files: {selectedList.Count})"); - ImGui.Separator(); - ImGuiHelpers.ScaledDummy(3); - using (ImRaii.Disabled(string.IsNullOrEmpty(_selectedJobEntry))) - { - - var restContent = availableContentRegion.X - ImGui.GetCursorPosX(); - using var group = ImRaii.Group(); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.ArrowRight, "Resolve Game Paths to used File Paths")) - { - _ = Task.Run(async () => - { - var paths = selectedList.ToArray(); - var resolved = await _ipcManager.Penumbra.ResolvePathsAsync(paths, []).ConfigureAwait(false); - _filePathResolve.Clear(); - - for (int i = 0; i < resolved.forward.Length; i++) - { - _filePathResolve[paths[i]] = resolved.forward[i]; - } - }); - } - ImGui.SameLine(); - ImGuiHelpers.ScaledDummy(20, 1); - ImGui.SameLine(); - using (ImRaii.Disabled(!_storedPathsToRemove.Any())) - { - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Remove selected Game Paths")) - { - foreach (var item in _storedPathsToRemove) - { - selectedList.Remove(item); - } - - _transientConfigService.Save(); - _transientResourceManager.RebuildSemiTransientResources(); - _filterFilePath = string.Empty; - _filterGamePath = string.Empty; - } - } - ImGui.SameLine(); - using (ImRaii.Disabled(!UiSharedService.CtrlPressed())) - { - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear ALL Game Paths")) - { - selectedList.Clear(); - _transientConfigService.Save(); - _transientResourceManager.RebuildSemiTransientResources(); - _filterFilePath = string.Empty; - _filterGamePath = string.Empty; - } - } - UiSharedService.AttachToolTip("Hold CTRL to delete all game paths from the displayed list" - + UiSharedService.TooltipSeparator + "You usually do not need to do this. All animation and VFX data will be automatically handled through Lightless."); - ImGuiHelpers.ScaledDummy(5); - ImGuiHelpers.ScaledDummy(30); - ImGui.SameLine(); - ImGui.SetNextItemWidth((restContent - 30) / 2f); - ImGui.InputTextWithHint("##filterGamePath", "Filter by Game Path", ref _filterGamePath, 255); - ImGui.SameLine(); - ImGui.SetNextItemWidth((restContent - 30) / 2f); - ImGui.InputTextWithHint("##filterFilePath", "Filter by File Path", ref _filterFilePath, 255); - - using (var dataTable = ImRaii.Table("##table", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.ScrollY | ImGuiTableFlags.RowBg)) - { - if (dataTable) - { - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 30); - ImGui.TableSetupColumn("Game Path", ImGuiTableColumnFlags.WidthFixed, (restContent - 30) / 2f); - ImGui.TableSetupColumn("File Path", ImGuiTableColumnFlags.WidthFixed, (restContent - 30) / 2f); - ImGui.TableSetupScrollFreeze(0, 1); - ImGui.TableHeadersRow(); - int id = 0; - foreach (var entry in selectedList) - { - if (!string.IsNullOrWhiteSpace(_filterGamePath) && !entry.Contains(_filterGamePath, StringComparison.OrdinalIgnoreCase)) - continue; - bool hasFileResolve = _filePathResolve.TryGetValue(entry, out var filePath); - - if (hasFileResolve && !string.IsNullOrEmpty(_filterFilePath) && !filePath!.Contains(_filterFilePath, StringComparison.OrdinalIgnoreCase)) - continue; - - using var imguiid = ImRaii.PushId(id++); - ImGui.TableNextColumn(); - bool isSelected = _storedPathsToRemove.Contains(entry, StringComparer.Ordinal); - if (ImGui.Checkbox("##", ref isSelected)) - { - if (isSelected) - _storedPathsToRemove.Add(entry); - else - _storedPathsToRemove.Remove(entry); - } - ImGui.TableNextColumn(); - ImGui.TextUnformatted(entry); - UiSharedService.AttachToolTip(entry + UiSharedService.TooltipSeparator + "Click to copy to clipboard"); - if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) - { - ImGui.SetClipboardText(entry); - } - ImGui.TableNextColumn(); - if (hasFileResolve) - { - ImGui.TextUnformatted(filePath ?? "Unk"); - UiSharedService.AttachToolTip(filePath ?? "Unk" + UiSharedService.TooltipSeparator + "Click to copy to clipboard"); - if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) - { - ImGui.SetClipboardText(filePath); - } - } - else - { - ImGui.TextUnformatted("-"); - UiSharedService.AttachToolTip("Resolve Game Paths to used File Paths to display the associated file paths."); - } - } - } - } - } + _storedPathsToRemove.Clear(); + _filePathResolve.Clear(); + _filterFilePath = string.Empty; + _filterGamePath = string.Empty; } } + private void DrawRecording() + { + DrawRecordingHelpSection(); + DrawRecordingControlButtons(); + + if (_transientResourceManager.IsTransientRecording) + { + DrawRecordingActiveWarning(); + } + + ImGuiHelpers.ScaledDummy(5); + DrawRecordingReviewControls(); + ImGuiHelpers.ScaledDummy(5); + DrawRecordedTransientsTable(); + } + + private static void DrawRecordingHelpSection() { UiSharedService.DrawTree("What is this? (Explanation / Help)", () => { @@ -377,6 +548,10 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase ImGuiColors.DalamudRed, 800); ImGuiHelpers.ScaledDummy(5); }); + } + + private void DrawRecordingControlButtons() + { using (ImRaii.Disabled(_transientResourceManager.IsTransientRecording)) { if (_uiSharedService.IconTextButton(FontAwesomeIcon.Play, "Start Transient Recording")) @@ -396,15 +571,18 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase _transientRecordCts.Cancel(); } } - if (_transientResourceManager.IsTransientRecording) - { - ImGui.SameLine(); - UiSharedService.ColorText($"RECORDING - Time Remaining: {_transientResourceManager.RecordTimeRemaining.Value}", UIColors.Get("LightlessYellow")); - ImGuiHelpers.ScaledDummy(5); - UiSharedService.DrawGroupedCenteredColorText("DO NOT CHANGE YOUR APPEARANCE OR MODS WHILE RECORDING, YOU CAN ACCIDENTALLY MAKE SOME OF YOUR APPEARANCE RELATED MODS PERMANENT.", ImGuiColors.DalamudRed, 800); - } + } + private void DrawRecordingActiveWarning() + { + ImGui.SameLine(); + UiSharedService.ColorText($"RECORDING - Time Remaining: {_transientResourceManager.RecordTimeRemaining.Value}", UIColors.Get("LightlessYellow")); ImGuiHelpers.ScaledDummy(5); + UiSharedService.DrawGroupedCenteredColorText("DO NOT CHANGE YOUR APPEARANCE OR MODS WHILE RECORDING, YOU CAN ACCIDENTALLY MAKE SOME OF YOUR APPEARANCE RELATED MODS PERMANENT.", ImGuiColors.DalamudRed, 800); + } + + private void DrawRecordingReviewControls() + { ImGui.Checkbox("Show previously added transient files in the recording", ref _showAlreadyAddedTransients); _uiSharedService.DrawHelpText("Use this only if you want to see what was previously already caught by Lightless"); ImGuiHelpers.ScaledDummy(5); @@ -425,49 +603,53 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase UiSharedService.DrawGroupedCenteredColorText("Please review the recorded mod files before saving and deselect files that got into the recording on accident.", UIColors.Get("LightlessYellow")); ImGuiHelpers.ScaledDummy(5); } + } - ImGuiHelpers.ScaledDummy(5); + private void DrawRecordedTransientsTable() + { var width = ImGui.GetContentRegionAvail(); using var table = ImRaii.Table("Recorded Transients", 4, ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); - if (table) + if (!table) { - int id = 0; - ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 30); - ImGui.TableSetupColumn("Owner", ImGuiTableColumnFlags.WidthFixed, 100); - ImGui.TableSetupColumn("Game Path", ImGuiTableColumnFlags.WidthFixed, (width.X - 30 - 100) / 2f); - ImGui.TableSetupColumn("File Path", ImGuiTableColumnFlags.WidthFixed, (width.X - 30 - 100) / 2f); - ImGui.TableSetupScrollFreeze(0, 1); - ImGui.TableHeadersRow(); - var transients = _transientResourceManager.RecordedTransients.ToList(); - transients.Reverse(); - foreach (var value in transients) - { - if (value.AlreadyTransient && !_showAlreadyAddedTransients) - continue; + return; + } - using var imguiid = ImRaii.PushId(id++); - if (value.AlreadyTransient) - { - ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); - } - ImGui.TableNextColumn(); - bool addTransient = value.AddTransient; - if (ImGui.Checkbox("##add", ref addTransient)) - { - value.AddTransient = addTransient; - } - ImGui.TableNextColumn(); - ImGui.TextUnformatted(value.Owner.Name); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(value.GamePath); - UiSharedService.AttachToolTip(value.GamePath); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(value.FilePath); - UiSharedService.AttachToolTip(value.FilePath); - if (value.AlreadyTransient) - { - ImGui.PopStyleColor(); - } + int id = 0; + ImGui.TableSetupColumn("", ImGuiTableColumnFlags.WidthFixed, 30); + ImGui.TableSetupColumn("Owner", ImGuiTableColumnFlags.WidthFixed, 100); + ImGui.TableSetupColumn("Game Path", ImGuiTableColumnFlags.WidthFixed, (width.X - 30 - 100) / 2f); + ImGui.TableSetupColumn("File Path", ImGuiTableColumnFlags.WidthFixed, (width.X - 30 - 100) / 2f); + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); + var transients = _transientResourceManager.RecordedTransients.ToList(); + transients.Reverse(); + foreach (var value in transients) + { + if (value.AlreadyTransient && !_showAlreadyAddedTransients) + continue; + + using var imguiid = ImRaii.PushId(id++); + if (value.AlreadyTransient) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey); + } + ImGui.TableNextColumn(); + bool addTransient = value.AddTransient; + if (ImGui.Checkbox("##add", ref addTransient)) + { + value.AddTransient = addTransient; + } + ImGui.TableNextColumn(); + ImGui.TextUnformatted(value.Owner.Name); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(value.GamePath); + UiSharedService.AttachToolTip(value.GamePath); + ImGui.TableNextColumn(); + ImGui.TextUnformatted(value.FilePath); + UiSharedService.AttachToolTip(value.FilePath); + if (value.AlreadyTransient) + { + ImGui.PopStyleColor(); } } } @@ -481,6 +663,8 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase if (_cachedAnalysis!.Count == 0) return; + EnsureTextureRows(); + bool isAnalyzing = _characterAnalyzer.IsAnalysisRunning; if (isAnalyzing) { @@ -513,31 +697,19 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase ImGui.Separator(); - ImGui.TextUnformatted("Total files:"); - ImGui.SameLine(); - ImGui.TextUnformatted(_cachedAnalysis!.Values.Sum(c => c.Values.Count).ToString()); - ImGui.SameLine(); - using (var font = ImRaii.PushFont(UiBuilder.IconFont)) - { - ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString()); - } - if (ImGui.IsItemHovered()) - { - string text = ""; - var groupedfiles = _cachedAnalysis.Values.SelectMany(f => f.Values).GroupBy(f => f.FileType, StringComparer.Ordinal); - text = string.Join(Environment.NewLine, groupedfiles.OrderBy(f => f.Key, StringComparer.Ordinal) - .Select(f => f.Key + ": " + f.Count() + " files, size: " + UiSharedService.ByteToString(f.Sum(v => v.OriginalSize)) - + ", compressed: " + UiSharedService.ByteToString(f.Sum(v => v.CompressedSize)))); - ImGui.SetTooltip(text); - } - ImGui.TextUnformatted("Total size (actual):"); - ImGui.SameLine(); - ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.OriginalSize)))); - ImGui.TextUnformatted("Total size (compressed for up/download only):"); - ImGui.SameLine(); - ImGui.TextUnformatted(UiSharedService.ByteToString(_cachedAnalysis!.Sum(c => c.Value.Sum(c => c.Value.CompressedSize)))); - ImGui.TextUnformatted($"Total modded model triangles: {_cachedAnalysis.Sum(c => c.Value.Sum(f => f.Value.Triangles))}"); - ImGui.Separator(); + var totalFileCount = _cachedAnalysis!.Values.Sum(c => c.Values.Count); + var totalActualSize = _cachedAnalysis.Sum(c => c.Value.Sum(entry => entry.Value.OriginalSize)); + var totalCompressedSize = _cachedAnalysis.Sum(c => c.Value.Sum(entry => entry.Value.CompressedSize)); + var totalTriangles = _cachedAnalysis.Sum(c => c.Value.Sum(entry => entry.Value.Triangles)); + var breakdown = string.Join(Environment.NewLine, + _cachedAnalysis.Values + .SelectMany(f => f.Values) + .GroupBy(f => f.FileType, StringComparer.Ordinal) + .OrderBy(f => f.Key, StringComparer.Ordinal) + .Select(f => $"{f.Key}: {f.Count()} files, size: {UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))}, compressed: {UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))}")); + + DrawAnalysisOverview(totalFileCount, totalActualSize, totalCompressedSize, totalTriangles, breakdown); + using var tabbar = ImRaii.TabBar("objectSelection"); foreach (var kvp in _cachedAnalysis) { @@ -549,221 +721,31 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase { var groupedfiles = kvp.Value.Select(v => v.Value).GroupBy(f => f.FileType, StringComparer.Ordinal).OrderBy(k => k.Key, StringComparer.Ordinal).ToList(); - ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, new Vector2(1f, 1f)); - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1f, 1f)); - - if (ImGui.BeginTable($"##fileStats_{kvp.Key}", 3, - ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.SizingFixedFit)) - { - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"Files for {kvp.Key}"); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(kvp.Value.Count.ToString()); - ImGui.SameLine(); - using (var font = ImRaii.PushFont(UiBuilder.IconFont)) - ImGui.TextUnformatted(FontAwesomeIcon.InfoCircle.ToIconString()); - if (ImGui.IsItemHovered()) - { - string text = string.Join(Environment.NewLine, groupedfiles.Select(f => - $"{f.Key}: {f.Count()} files, size: {UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))}, compressed: {UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))}")); - ImGui.SetTooltip(text); - } - ImGui.TableNextColumn(); - - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"{kvp.Key} size (actual):"); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.OriginalSize))); - ImGui.TableNextColumn(); - - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"{kvp.Key} size (compressed for up/download only):"); - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(UiSharedService.ByteToString(kvp.Value.Sum(c => c.Value.CompressedSize))); - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f); - ImGui.TableNextColumn(); - - var vramUsage = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal)); - if (vramUsage != null) - { - var actualVramUsage = vramUsage.Sum(f => f.OriginalSize); - - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"{kvp.Key} VRAM usage:"); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(UiSharedService.ByteToString(actualVramUsage)); - ImGui.TableNextColumn(); - - if (_playerPerformanceConfig.Current.WarnOnExceedingThresholds - || _playerPerformanceConfig.Current.ShowPerformanceIndicator) - { - var currentVramWarning = _playerPerformanceConfig.Current.VRAMSizeWarningThresholdMiB; - - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted("Configured VRAM threshold:"); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"{currentVramWarning} MiB."); - ImGui.TableNextColumn(); - if (currentVramWarning * 1024 * 1024 < actualVramUsage) - { - UiSharedService.ColorText( - $"You exceed your own threshold by {UiSharedService.ByteToString(actualVramUsage - (currentVramWarning * 1024 * 1024))}", - UIColors.Get("LightlessYellow")); - } - } - } - - var actualTriCount = kvp.Value.Sum(f => f.Value.Triangles); - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"{kvp.Key} modded model triangles:"); - ImGui.TableNextColumn(); - ImGui.TextUnformatted(actualTriCount.ToString()); - ImGui.TableNextColumn(); - - if (_playerPerformanceConfig.Current.WarnOnExceedingThresholds - || _playerPerformanceConfig.Current.ShowPerformanceIndicator) - { - var currentTriWarning = _playerPerformanceConfig.Current.TrisWarningThresholdThousands; - - ImGui.TableNextRow(); - ImGui.TableNextColumn(); - ImGui.TextUnformatted("Configured triangle threshold:"); - ImGui.TableNextColumn(); - ImGui.TextUnformatted($"{currentTriWarning * 1000} triangles."); - ImGui.TableNextColumn(); - if (currentTriWarning * 1000 < actualTriCount) - { - UiSharedService.ColorText( - $"You exceed your own threshold by {actualTriCount - (currentTriWarning * 1000)}", - UIColors.Get("LightlessYellow")); - } - } - - ImGui.EndTable(); - } - - ImGui.PopStyleVar(2); - - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f); - - _uiSharedService.MediumText("Selected file:", UIColors.Get("LightlessBlue")); - ImGui.SameLine(); - _uiSharedService.MediumText(_selectedHash, UIColors.Get("LightlessYellow")); - - if (_cachedAnalysis[_selectedObjectTab].TryGetValue(_selectedHash, out CharacterAnalyzer.FileDataEntry? item)) - { - var filePaths = item.FilePaths; - UiSharedService.ColorText("Local file path:", UIColors.Get("LightlessBlue")); - ImGui.SameLine(); - UiSharedService.TextWrapped(filePaths[0]); - if (filePaths.Count > 1) - { - ImGui.SameLine(); - ImGui.TextUnformatted($"(and {filePaths.Count - 1} more)"); - ImGui.SameLine(); - _uiSharedService.IconText(FontAwesomeIcon.InfoCircle); - UiSharedService.AttachToolTip(string.Join(Environment.NewLine, filePaths.Skip(1))); - } - - var gamepaths = item.GamePaths; - UiSharedService.ColorText("Used by game path:", UIColors.Get("LightlessBlue")); - ImGui.SameLine(); - UiSharedService.TextWrapped(gamepaths[0]); - if (gamepaths.Count > 1) - { - ImGui.SameLine(); - ImGui.TextUnformatted($"(and {gamepaths.Count - 1} more)"); - ImGui.SameLine(); - _uiSharedService.IconText(FontAwesomeIcon.InfoCircle); - UiSharedService.AttachToolTip(string.Join(Environment.NewLine, gamepaths.Skip(1))); - } - } - - ImGui.Separator(); + DrawObjectOverview(kvp.Key, kvp.Value, groupedfiles); if (_selectedObjectTab != kvp.Key) { _selectedHash = string.Empty; _selectedObjectTab = kvp.Key; _selectedFileTypeTab = string.Empty; - _enableBc7ConversionMode = false; - _texturesToConvert.Clear(); } - using var fileTabBar = ImRaii.TabBar("fileTabs"); + var otherFileGroups = groupedfiles + .Where(g => !string.Equals(g.Key, "tex", StringComparison.Ordinal)) + .ToList(); - foreach (IGrouping? fileGroup in groupedfiles) + if (!string.IsNullOrEmpty(_selectedFileTypeTab) && + otherFileGroups.TrueForAll(g => !string.Equals(g.Key, _selectedFileTypeTab, StringComparison.Ordinal))) { - string fileGroupText = fileGroup.Key + " [" + fileGroup.Count() + "]"; - var requiresCompute = fileGroup.Any(k => !k.IsComputed); - using var tabcol = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.Color(UIColors.Get("LightlessYellow")), requiresCompute); - if (requiresCompute) - { - fileGroupText += " (!)"; - } - ImRaii.IEndObject fileTab; - using (var textcol = ImRaii.PushColor(ImGuiCol.Text, UiSharedService.Color(new(0, 0, 0, 1)), - requiresCompute && !string.Equals(_selectedFileTypeTab, fileGroup.Key, StringComparison.Ordinal))) - { - fileTab = ImRaii.TabItem(fileGroupText + "###" + fileGroup.Key); - } - - if (!fileTab) { fileTab.Dispose(); continue; } - - if (!string.Equals(fileGroup.Key, _selectedFileTypeTab, StringComparison.Ordinal)) - { - _selectedFileTypeTab = fileGroup.Key; - _selectedHash = string.Empty; - _enableBc7ConversionMode = false; - _texturesToConvert.Clear(); - } - - ImGui.TextUnformatted($"{fileGroup.Key} files"); - ImGui.SameLine(); - ImGui.TextUnformatted(fileGroup.Count().ToString()); - - ImGui.TextUnformatted($"{fileGroup.Key} files size (actual):"); - ImGui.SameLine(); - ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.OriginalSize))); - - ImGui.TextUnformatted($"{fileGroup.Key} files size (compressed for up/download only):"); - ImGui.SameLine(); - ImGui.TextUnformatted(UiSharedService.ByteToString(fileGroup.Sum(c => c.CompressedSize))); - - if (string.Equals(_selectedFileTypeTab, "tex", StringComparison.Ordinal)) - { - ImGui.Checkbox("Enable BC7 Conversion Mode", ref _enableBc7ConversionMode); - if (_enableBc7ConversionMode) - { - UiSharedService.ColorText("WARNING BC7 CONVERSION:", UIColors.Get("LightlessYellow")); - ImGui.SameLine(); - UiSharedService.ColorText("Converting textures to BC7 is irreversible!", ImGuiColors.DalamudRed); - UiSharedService.ColorTextWrapped("- Converting textures to BC7 will reduce their size (compressed and uncompressed) drastically. It is recommended to be used for large (4k+) textures." + - Environment.NewLine + "- Some textures, especially ones utilizing colorsets, might not be suited for BC7 conversion and might produce visual artifacts." + - Environment.NewLine + "- Before converting textures, make sure to have the original files of the mod you are converting so you can reimport it in case of issues." + - Environment.NewLine + "- Conversion will convert all found texture duplicates (entries with more than 1 file path) automatically." + - Environment.NewLine + "- Converting textures to BC7 is a very expensive operation and, depending on the amount of textures to convert, will take a while to complete." - , UIColors.Get("LightlessYellow")); - if (_texturesToConvert.Count > 0 && _uiSharedService.IconTextButton(FontAwesomeIcon.PlayCircle, "Start conversion of " + _texturesToConvert.Count + " texture(s)")) - { - _conversionCancellationTokenSource = _conversionCancellationTokenSource.CancelRecreate(); - _conversionTask = _ipcManager.Penumbra.ConvertTextureFiles(_logger, _texturesToConvert, _conversionProgress, _conversionCancellationTokenSource.Token); - } - } - } - - ImGui.Separator(); - DrawTable(fileGroup); - - fileTab.Dispose(); + _selectedFileTypeTab = string.Empty; } + + if (string.IsNullOrEmpty(_selectedFileTypeTab) && otherFileGroups.Count > 0) + { + _selectedFileTypeTab = otherFileGroups[0].Key; + } + + DrawTextureWorkspace(kvp.Key, otherFileGroups); } } } @@ -772,146 +754,1883 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase { _hasUpdate = true; _selectedHash = string.Empty; - _enableBc7ConversionMode = false; - _texturesToConvert.Clear(); + _selectedTextureKey = string.Empty; + _selectedTextureKeys.Clear(); + _textureSelections.Clear(); + ResetTextureFilters(); + _textureRowsDirty = true; + _conversionFailed = false; } protected override void Dispose(bool disposing) { base.Dispose(disposing); + foreach (var preview in _texturePreviews.Values) + { + preview.Texture?.Dispose(); + } + _texturePreviews.Clear(); _conversionProgress.ProgressChanged -= ConversionProgress_ProgressChanged; } - private void ConversionProgress_ProgressChanged(object? sender, (string, int) e) + private void ConversionProgress_ProgressChanged(object? sender, TextureConversionProgress e) { - _conversionCurrentFileName = e.Item1; - _conversionCurrentFileProgress = e.Item2; + _lastConversionProgress = e; + _conversionTotalJobs = e.Total; + _conversionCurrentFileName = Path.GetFileName(e.CurrentJob.OutputFile); + _conversionCurrentFileProgress = Math.Min(e.Completed + 1, e.Total); + } + + private void EnsureTextureRows() + { + if (!_textureRowsDirty || _cachedAnalysis == null) + { + return; + } + + _textureRows.Clear(); + HashSet validKeys = new(StringComparer.OrdinalIgnoreCase); + + foreach (var (objectKind, entries) in _cachedAnalysis) + { + foreach (var entry in entries.Values) + { + if (!string.Equals(entry.FileType, "tex", StringComparison.Ordinal)) + { + continue; + } + + if (entry.FilePaths.Count == 0) + { + continue; + } + + var primaryFile = entry.FilePaths[0]; + var duplicatePaths = entry.FilePaths.Skip(1).ToList(); + var primaryGamePath = entry.GamePaths.FirstOrDefault() ?? string.Empty; + var classificationPath = string.IsNullOrEmpty(primaryGamePath) ? primaryFile : primaryGamePath; + var mapKind = _textureMetadataHelper.DetermineMapKind(primaryGamePath, primaryFile); + var category = _textureMetadataHelper.DetermineCategory(classificationPath); + var slot = _textureMetadataHelper.DetermineSlot(category, classificationPath); + var format = entry.Format.Value; + var suggestion = _textureMetadataHelper.GetSuggestedTarget(format, mapKind); + TextureCompressionTarget? currentTarget = _textureMetadataHelper.TryMapFormatToTarget(format, out var mappedTarget) + ? mappedTarget + : null; + var displayName = Path.GetFileName(primaryFile); + + var row = new TextureRow( + objectKind, + entry, + primaryFile, + duplicatePaths, + entry.GamePaths.ToList(), + primaryGamePath, + format, + mapKind, + category, + slot, + displayName, + currentTarget, + suggestion?.Target, + suggestion?.Reason); + + validKeys.Add(row.Key); + _textureRows.Add(row); + + if (row.IsAlreadyCompressed) + { + _selectedTextureKeys.Remove(row.Key); + _textureSelections.Remove(row.Key); + } + } + } + + _textureRows.Sort((a, b) => + { + var comp = a.ObjectKind.CompareTo(b.ObjectKind); + if (comp != 0) + return comp; + + comp = string.Compare(a.Slot, b.Slot, StringComparison.OrdinalIgnoreCase); + if (comp != 0) + return comp; + + return string.Compare(a.DisplayName, b.DisplayName, StringComparison.OrdinalIgnoreCase); + }); + + _selectedTextureKeys.RemoveWhere(key => !validKeys.Contains(key)); + + foreach (var key in _texturePreviews.Keys.ToArray()) + { + if (!validKeys.Contains(key) && _texturePreviews.TryGetValue(key, out var preview)) + { + preview.Texture?.Dispose(); + _texturePreviews.Remove(key); + } + } + + foreach (var key in _textureSelections.Keys.ToArray()) + { + if (!validKeys.Contains(key)) + { + _textureSelections.Remove(key); + continue; + } + + _textureSelections[key] = _textureCompressionService.NormalizeTarget(_textureSelections[key]); + } + + if (!string.IsNullOrEmpty(_selectedTextureKey) && !validKeys.Contains(_selectedTextureKey)) + { + _selectedTextureKey = string.Empty; + } + + _textureRowsDirty = false; + } + + private static string MakeTextureKey(ObjectKind objectKind, string primaryFilePath) => + $"{objectKind}|{primaryFilePath}".ToLowerInvariant(); + + private void ResetTextureFilters() + { + _textureCategoryFilter = null; + _textureSlotFilter = "All"; + _textureMapFilter = null; + _textureTargetFilter = null; + _textureSearch = string.Empty; + } + + private void DrawAnalysisOverview(int totalFiles, long totalActualSize, long totalCompressedSize, long totalTriangles, string breakdownTooltip) + { + var scale = ImGuiHelpers.GlobalScale; + var accent = UIColors.Get("LightlessGreen"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.18f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.4f); + var infoColor = ImGuiColors.DalamudGrey; + var diff = totalActualSize - totalCompressedSize; + string? diffText = null; + Vector4? diffColor = null; + if (diff > 0) + { + diffText = $"Saved {UiSharedService.ByteToString(diff)}"; + diffColor = UIColors.Get("LightlessGreen"); + } + else if (diff < 0) + { + diffText = $"Over by {UiSharedService.ByteToString(Math.Abs(diff))}"; + diffColor = UIColors.Get("DimRed"); + } + + var summaryHeight = MathF.Max(ImGui.GetTextLineHeightWithSpacing() * 2.4f, 44f * scale); + + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 6f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(18f * scale, 4f * scale))) + using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(accentBg))) + using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(accentBorder))) + using (var child = ImRaii.Child("analysisOverview", new Vector2(-1f, summaryHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) + { + if (child) + { + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(8f * scale, 4f * scale))) + { + if (ImGui.BeginTable("analysisOverviewTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.PadOuterX | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.NoHostExtendX)) + { + ImGui.TableNextRow(); + DrawSummaryCell(FontAwesomeIcon.ListUl, accent, $"{totalFiles:N0}", totalFiles == 1 ? "Tracked file" : "Tracked files", infoColor, scale, tooltip: breakdownTooltip); + DrawSummaryCell(FontAwesomeIcon.FileArchive, ImGuiColors.DalamudGrey, UiSharedService.ByteToString(totalActualSize), "Actual size", infoColor, scale); + DrawSummaryCell(FontAwesomeIcon.CompressArrowsAlt, UIColors.Get("LightlessYellow2"), UiSharedService.ByteToString(totalCompressedSize), "Compressed size", infoColor, scale, diffText, diffColor); + DrawSummaryCell(FontAwesomeIcon.ChartLine, UIColors.Get("LightlessPurple"), totalTriangles.ToString("N0", CultureInfo.InvariantCulture), "Modded triangles", infoColor, scale); + ImGui.EndTable(); + } + } + } + } + + ImGuiHelpers.ScaledDummy(6); + } + + private void DrawObjectOverview( + ObjectKind objectKind, + IReadOnlyDictionary entries, + IReadOnlyList> groupedFiles) + { + var scale = ImGuiHelpers.GlobalScale; + var accent = UIColors.Get("LightlessPurple"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.16f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.32f); + var infoColor = ImGuiColors.DalamudGrey; + var fileCount = entries.Count; + var actualSize = entries.Sum(c => c.Value.OriginalSize); + var compressedSize = entries.Sum(c => c.Value.CompressedSize); + var triangles = entries.Sum(c => c.Value.Triangles); + var breakdown = string.Join(Environment.NewLine, + groupedFiles.Select(f => + $"{f.Key}: {f.Count()} files, size: {UiSharedService.ByteToString(f.Sum(v => v.OriginalSize))}, compressed: {UiSharedService.ByteToString(f.Sum(v => v.CompressedSize))}")); + + var savings = actualSize - compressedSize; + string? compressedExtra = null; + Vector4? compressedExtraColor = null; + if (savings > 0) + { + compressedExtra = $"Saved {UiSharedService.ByteToString(savings)}"; + compressedExtraColor = UIColors.Get("LightlessGreen"); + } + else if (savings < 0) + { + compressedExtra = $"Over by {UiSharedService.ByteToString(Math.Abs(savings))}"; + compressedExtraColor = UIColors.Get("DimRed"); + } + + long actualVram = 0; + var vramGroup = groupedFiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal)); + if (vramGroup != null) + { + actualVram = vramGroup.Sum(f => f.OriginalSize); + } + + string? vramExtra = null; + Vector4? vramExtraColor = null; + var vramSub = vramGroup != null ? "VRAM usage" : "VRAM usage (no textures)"; + var showThresholds = _playerPerformanceConfig.Current.WarnOnExceedingThresholds + || _playerPerformanceConfig.Current.ShowPerformanceIndicator; + if (showThresholds && actualVram > 0) + { + var thresholdBytes = Math.Max(0, _playerPerformanceConfig.Current.VRAMSizeWarningThresholdMiB) * 1024L * 1024L; + if (thresholdBytes > 0) + { + if (actualVram > thresholdBytes) + { + vramExtra = $"Over by {UiSharedService.ByteToString(actualVram - thresholdBytes)}"; + vramExtraColor = UIColors.Get("LightlessYellow"); + } + else + { + vramExtra = $"Remaining {UiSharedService.ByteToString(thresholdBytes - actualVram)}"; + vramExtraColor = UIColors.Get("LightlessGreen"); + } + } + } + + string? triExtra = null; + Vector4? triExtraColor = null; + if (showThresholds) + { + var triThreshold = Math.Max(0, _playerPerformanceConfig.Current.TrisWarningThresholdThousands) * 1000; + if (triThreshold > 0) + { + if (triangles > triThreshold) + { + triExtra = $"Over by {(triangles - triThreshold).ToString("N0", CultureInfo.InvariantCulture)}"; + triExtraColor = UIColors.Get("LightlessYellow"); + } + else + { + triExtra = $"Remaining {(triThreshold - triangles).ToString("N0", CultureInfo.InvariantCulture)}"; + triExtraColor = UIColors.Get("LightlessGreen"); + } + } + } + + var summaryHeight = MathF.Max(ImGui.GetTextLineHeightWithSpacing() * 2.4f, 46f * scale); + var availableWidth = ImGui.GetContentRegionAvail().X; + var summaryWidth = objectKind == ObjectKind.Player + ? availableWidth + : MathF.Min(availableWidth, 760f * scale); + + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 5f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(18f * scale, 4f * scale))) + using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(accentBg))) + using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(accentBorder))) + using (var child = ImRaii.Child($"objectOverview##{objectKind}", new Vector2(summaryWidth, summaryHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) + { + if (child) + { + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(8f * scale, 4f * scale))) + { + if (ImGui.BeginTable($"objectOverviewTable##{objectKind}", 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.PadOuterX | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.NoHostExtendX)) + { + ImGui.TableNextRow(); + DrawSummaryCell(FontAwesomeIcon.ClipboardList, accent, $"{fileCount:N0}", $"{objectKind} files", infoColor, scale, tooltip: breakdown); + DrawSummaryCell(FontAwesomeIcon.FileArchive, ImGuiColors.DalamudGrey, UiSharedService.ByteToString(actualSize), "Actual size", infoColor, scale); + DrawSummaryCell(FontAwesomeIcon.CompressArrowsAlt, UIColors.Get("LightlessYellow2"), UiSharedService.ByteToString(compressedSize), "Compressed size", infoColor, scale, compressedExtra, compressedExtraColor); + DrawSummaryCell(FontAwesomeIcon.Memory, UIColors.Get("LightlessBlue"), UiSharedService.ByteToString(actualVram), vramSub, infoColor, scale, vramExtra, vramExtraColor); + DrawSummaryCell(FontAwesomeIcon.ProjectDiagram, UIColors.Get("LightlessPurple"), triangles.ToString("N0", CultureInfo.InvariantCulture), "Modded triangles", infoColor, scale, triExtra, triExtraColor); + ImGui.EndTable(); + } + } + } + } + + ImGuiHelpers.ScaledDummy(4); + } + + private enum TextureWorkspaceTab + { + Textures, + OtherFiles + } + + private sealed record TextureRow( + ObjectKind ObjectKind, + CharacterAnalyzer.FileDataEntry Entry, + string PrimaryFilePath, + IReadOnlyList DuplicateFilePaths, + IReadOnlyList GamePaths, + string PrimaryGamePath, + string Format, + TextureMapKind MapKind, + TextureUsageCategory Category, + string Slot, + string DisplayName, + TextureCompressionTarget? CurrentTarget, + TextureCompressionTarget? SuggestedTarget, + string? SuggestionReason) + { + public string Key { get; } = MakeTextureKey(ObjectKind, PrimaryFilePath); + public string Hash => Entry.Hash; + public long OriginalSize => Entry.OriginalSize; + public long CompressedSize => Entry.CompressedSize; + public bool IsComputed => Entry.IsComputed; + public bool IsAlreadyCompressed => CurrentTarget.HasValue; + } + + private sealed class TexturePreviewState + { + public Task? LoadTask { get; set; } + public IDalamudTextureWrap? Texture { get; set; } + public string? ErrorMessage { get; set; } + public DateTime LastAccessUtc { get; set; } = DateTime.UtcNow; + } + + private void DrawTextureWorkspace(ObjectKind objectKind, IReadOnlyList> otherFileGroups) + { + if (!_textureWorkspaceTabs.ContainsKey(objectKind)) + { + _textureWorkspaceTabs[objectKind] = TextureWorkspaceTab.Textures; + } + + if (otherFileGroups.Count == 0) + { + _textureWorkspaceTabs[objectKind] = TextureWorkspaceTab.Textures; + DrawTextureTabContent(objectKind); + return; + } + + using var tabBar = ImRaii.TabBar($"textureWorkspaceTabs##{objectKind}"); + + using (var texturesTab = ImRaii.TabItem($"Textures###textures_{objectKind}")) + { + if (texturesTab) + { + if (_textureWorkspaceTabs[objectKind] != TextureWorkspaceTab.Textures) + { + _textureWorkspaceTabs[objectKind] = TextureWorkspaceTab.Textures; + } + DrawTextureTabContent(objectKind); + } + } + + using (var otherFilesTab = ImRaii.TabItem($"Other file types###other_{objectKind}")) + { + if (otherFilesTab) + { + if (_textureWorkspaceTabs[objectKind] != TextureWorkspaceTab.OtherFiles) + { + _textureWorkspaceTabs[objectKind] = TextureWorkspaceTab.OtherFiles; + } + DrawOtherFileWorkspace(otherFileGroups); + } + } + } + + private void DrawTextureTabContent(ObjectKind objectKind) + { + var scale = ImGuiHelpers.GlobalScale; + var objectRows = _textureRows.Where(row => row.ObjectKind == objectKind).ToList(); + var hasAnyTextureRows = objectRows.Count > 0; + var availableCategories = objectRows.Select(row => row.Category) + .Distinct() + .OrderBy(c => c.ToString(), StringComparer.Ordinal) + .ToList(); + var availableSlots = objectRows + .Select(row => row.Slot) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(s => s, StringComparer.OrdinalIgnoreCase) + .ToList(); + var availableMapKinds = objectRows.Select(row => row.MapKind) + .Distinct() + .OrderBy(m => m.ToString(), StringComparer.Ordinal) + .ToList(); + + var totalTextureCount = objectRows.Count; + var totalTextureOriginal = objectRows.Sum(row => row.OriginalSize); + var totalTextureCompressed = objectRows.Sum(row => row.CompressedSize); + + IEnumerable filtered = objectRows; + + if (_textureCategoryFilter is { } categoryFilter) + { + filtered = filtered.Where(row => row.Category == categoryFilter); + } + + if (!string.Equals(_textureSlotFilter, "All", StringComparison.Ordinal)) + { + filtered = filtered.Where(row => string.Equals(row.Slot, _textureSlotFilter, StringComparison.OrdinalIgnoreCase)); + } + + if (_textureMapFilter is { } mapFilter) + { + filtered = filtered.Where(row => row.MapKind == mapFilter); + } + + if (_textureTargetFilter is { } targetFilter) + { + filtered = filtered.Where(row => + (row.CurrentTarget != null && row.CurrentTarget == targetFilter) || + (row.CurrentTarget == null && row.SuggestedTarget == targetFilter)); + } + + if (!string.IsNullOrWhiteSpace(_textureSearch)) + { + var term = _textureSearch.Trim(); + filtered = filtered.Where(row => + row.DisplayName.Contains(term, StringComparison.OrdinalIgnoreCase) || + row.PrimaryGamePath.Contains(term, StringComparison.OrdinalIgnoreCase) || + row.Hash.Contains(term, StringComparison.OrdinalIgnoreCase)); + } + + var rows = filtered.ToList(); + + if (!string.IsNullOrEmpty(_selectedTextureKey) && rows.All(r => r.Key != _selectedTextureKey)) + { + _selectedTextureKey = rows.FirstOrDefault()?.Key ?? string.Empty; + } + + var totalOriginal = rows.Sum(r => r.OriginalSize); + var totalCompressed = rows.Sum(r => r.CompressedSize); + + var availableSize = ImGui.GetContentRegionAvail(); + var windowPos = ImGui.GetWindowPos(); + var spacingX = ImGui.GetStyle().ItemSpacing.X; + var splitterWidth = 6f * scale; + const float minFilterWidth = MinTextureFilterPaneWidth; + const float minDetailWidth = MinTextureDetailPaneWidth; + const float minCenterWidth = 340f; + + var dynamicFilterMax = Math.Max(minFilterWidth, availableSize.X - minDetailWidth - minCenterWidth - 2 * (splitterWidth + spacingX)); + var filterMaxBound = Math.Min(MaxTextureFilterPaneWidth, dynamicFilterMax); + var filterWidth = Math.Clamp(_textureFilterPaneWidth, minFilterWidth, filterMaxBound); + + var dynamicDetailMax = Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - 2 * (splitterWidth + spacingX)); + var detailMaxBound = Math.Min(MaxTextureDetailPaneWidth, dynamicDetailMax); + var detailWidth = Math.Clamp(_textureDetailPaneWidth, minDetailWidth, detailMaxBound); + + var centerWidth = availableSize.X - filterWidth - detailWidth - 2 * (splitterWidth + spacingX); + + if (centerWidth < minCenterWidth) + { + var deficit = minCenterWidth - centerWidth; + detailWidth = Math.Clamp(detailWidth - deficit, minDetailWidth, + Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - 2 * (splitterWidth + spacingX)))); + centerWidth = availableSize.X - filterWidth - detailWidth - 2 * (splitterWidth + spacingX); + if (centerWidth < minCenterWidth) + { + deficit = minCenterWidth - centerWidth; + filterWidth = Math.Clamp(filterWidth - deficit, minFilterWidth, + Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - detailWidth - minCenterWidth - 2 * (splitterWidth + spacingX)))); + detailWidth = Math.Clamp(detailWidth, minDetailWidth, + Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - filterWidth - minCenterWidth - 2 * (splitterWidth + spacingX)))); + centerWidth = availableSize.X - filterWidth - detailWidth - 2 * (splitterWidth + spacingX); + if (centerWidth < minCenterWidth) + { + centerWidth = minCenterWidth; + } + } + } + + _textureFilterPaneWidth = filterWidth; + _textureDetailPaneWidth = detailWidth; + + ImGui.BeginGroup(); + using (var filters = ImRaii.Child("textureFilters", new Vector2(filterWidth, 0), true)) + { + if (filters) + { + DrawTextureFilters( + availableCategories, + availableSlots, + availableMapKinds, + totalTextureCount, + totalTextureOriginal, + totalTextureCompressed); + } + } + ImGui.EndGroup(); + + var filterMin = ImGui.GetItemRectMin(); + var filterMax = ImGui.GetItemRectMax(); + var filterHeight = filterMax.Y - filterMin.Y; + var filterTopLocal = filterMin - windowPos; + var maxFilterResize = Math.Min(MaxTextureFilterPaneWidth, Math.Max(minFilterWidth, availableSize.X - minCenterWidth - minDetailWidth - 2 * (splitterWidth + spacingX))); + DrawVerticalResizeHandle("##textureFilterSplitter", filterTopLocal.Y, filterHeight, ref _textureFilterPaneWidth, minFilterWidth, maxFilterResize); + + TextureRow? selectedRow; + ImGui.BeginGroup(); + using (var tableChild = ImRaii.Child("textureTableArea", new Vector2(centerWidth, 0), false)) + { + selectedRow = DrawTextureTable(rows, totalOriginal, totalCompressed, hasAnyTextureRows); + } + ImGui.EndGroup(); + + var tableMin = ImGui.GetItemRectMin(); + var tableMax = ImGui.GetItemRectMax(); + var tableHeight = tableMax.Y - tableMin.Y; + var tableTopLocal = tableMin - windowPos; + var maxDetailResize = Math.Min(MaxTextureDetailPaneWidth, Math.Max(minDetailWidth, availableSize.X - _textureFilterPaneWidth - minCenterWidth - 2 * (splitterWidth + spacingX))); + DrawVerticalResizeHandle("##textureDetailSplitter", tableTopLocal.Y, tableHeight, ref _textureDetailPaneWidth, minDetailWidth, maxDetailResize, invert: true); + + ImGui.BeginGroup(); + using (var detailChild = ImRaii.Child("textureDetailPane", new Vector2(detailWidth, 0), true)) + { + DrawTextureDetail(selectedRow); + } + ImGui.EndGroup(); + } + + private void DrawTextureFilters( + IReadOnlyList categories, + IReadOnlyList slots, + IReadOnlyList mapKinds, + int totalTextureCount, + long totalTextureOriginal, + long totalTextureCompressed) + { + var scale = ImGuiHelpers.GlobalScale; + var accent = UIColors.Get("LightlessBlue"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.14f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.35f); + var infoColor = ImGuiColors.DalamudGrey; + + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 6f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(18f * scale, 4f * scale))) + using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(accentBg))) + using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(accentBorder))) + { + var lineHeight = ImGui.GetTextLineHeightWithSpacing(); + var summaryHeight = MathF.Max(lineHeight * 2.4f, ImGui.GetFrameHeightWithSpacing() * 2.2f); + using (var totals = ImRaii.Child("textureTotalsSummary", new Vector2(-1f, summaryHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) + { + if (totals) + { + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(8f * scale, 4f * scale))) + { + if (ImGui.BeginTable("textureTotalsSummaryTable", 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.PadOuterX | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.NoHostExtendX)) + { + ImGui.TableNextRow(); + DrawSummaryCell(FontAwesomeIcon.Images, accent, $"{totalTextureCount:N0}", totalTextureCount == 1 ? "tex file" : "tex files", infoColor, scale); + DrawSummaryCell(FontAwesomeIcon.FileArchive, ImGuiColors.DalamudGrey, UiSharedService.ByteToString(totalTextureOriginal), "Actual size", infoColor, scale); + DrawSummaryCell(FontAwesomeIcon.CompressArrowsAlt, UIColors.Get("LightlessYellow2"), UiSharedService.ByteToString(totalTextureCompressed), "Compressed size", infoColor, scale); + ImGui.EndTable(); + } + } + } + } + } + + ImGuiHelpers.ScaledDummy(1); + + ImGui.TextUnformatted("Filters"); + ImGui.Separator(); + + ImGui.SetNextItemWidth(-1); + ImGui.InputTextWithHint("##textureSearch", "Search hash, path, or file name...", ref _textureSearch, 256); + + ImGuiHelpers.ScaledDummy(6); + + DrawEnumFilterCombo("Category", "All Categories", ref _textureCategoryFilter, categories); + DrawStringFilterCombo("Slot", ref _textureSlotFilter, slots, "All"); + DrawEnumFilterCombo("Map Type", "All Map Types", ref _textureMapFilter, mapKinds); + + if (_textureTargetFilter.HasValue && !_textureCompressionService.IsTargetSelectable(_textureTargetFilter.Value)) + { + _textureTargetFilter = null; + } + + DrawEnumFilterCombo("Compression", "Any Compression", ref _textureTargetFilter, _textureCompressionService.SelectableTargets); + + ImGuiHelpers.ScaledDummy(8); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Undo, "Reset filters")) + { + ResetTextureFilters(); + } + } + + private static void DrawEnumFilterCombo( + string label, + string allLabel, + ref T? currentSelection, + IEnumerable options) + where T : struct, Enum + { + var displayLabel = currentSelection?.ToString() ?? allLabel; + if (!ImGui.BeginCombo(label, displayLabel)) + { + return; + } + + bool noSelection = !currentSelection.HasValue; + if (ImGui.Selectable(allLabel, noSelection)) + { + currentSelection = null; + } + if (noSelection) + { + ImGui.SetItemDefaultFocus(); + } + + var comparer = EqualityComparer.Default; + foreach (var option in options) + { + bool selected = currentSelection.HasValue && comparer.Equals(currentSelection.Value, option); + if (ImGui.Selectable(option.ToString(), selected)) + { + currentSelection = option; + } + if (selected) + { + ImGui.SetItemDefaultFocus(); + } + } + + ImGui.EndCombo(); + } + + private static void DrawStringFilterCombo( + string label, + ref string currentSelection, + IEnumerable options, + string allLabel) + { + var displayLabel = string.IsNullOrEmpty(currentSelection) || string.Equals(currentSelection, allLabel, StringComparison.Ordinal) + ? allLabel + : currentSelection; + if (!ImGui.BeginCombo(label, displayLabel)) + { + return; + } + + bool allSelected = string.Equals(currentSelection, allLabel, StringComparison.Ordinal); + if (ImGui.Selectable(allLabel, allSelected)) + { + currentSelection = allLabel; + } + if (allSelected) + { + ImGui.SetItemDefaultFocus(); + } + + foreach (var option in options) + { + bool selected = string.Equals(currentSelection, option, StringComparison.OrdinalIgnoreCase); + if (ImGui.Selectable(option, selected)) + { + currentSelection = option; + } + if (selected) + { + ImGui.SetItemDefaultFocus(); + } + } + + ImGui.EndCombo(); + } + + private void DrawSummaryCell( + FontAwesomeIcon icon, + Vector4 iconColor, + string mainText, + string subText, + Vector4 subColor, + float scale, + string? extraText = null, + Vector4? extraColor = null, + string? tooltip = null) + { + ImGui.TableNextColumn(); + var spacing = new Vector2(6f * scale, 2f * scale); + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) + { + ImGui.BeginGroup(); + _uiSharedService.IconText(icon, iconColor); + ImGui.SameLine(0f, 4f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, iconColor)) + { + ImGui.TextUnformatted(mainText); + } + using (ImRaii.PushColor(ImGuiCol.Text, subColor)) + { + ImGui.TextUnformatted(subText); + } + if (!string.IsNullOrWhiteSpace(extraText)) + { + ImGui.SameLine(0f, 4f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, extraColor ?? subColor)) + { + ImGui.TextUnformatted(extraText); + } + } + ImGui.EndGroup(); + } + + if (!string.IsNullOrWhiteSpace(tooltip) && ImGui.IsItemHovered()) + { + ImGui.SetTooltip(tooltip); + } + } + + private void DrawOtherFileWorkspace(IReadOnlyList> otherFileGroups) + { + if (otherFileGroups.Count == 0) + { + return; + } + + var scale = ImGuiHelpers.GlobalScale; + + ImGuiHelpers.ScaledDummy(8); + var accent = UIColors.Get("LightlessBlue"); + var sectionAvail = ImGui.GetContentRegionAvail().Y; + IGrouping? activeGroup = null; + + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 6f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(12f * scale, 4f * scale))) + using (var child = ImRaii.Child("otherFileTypes", new Vector2(-1f, sectionAvail - (SelectedFilePanelLogicalHeight * scale) - 12f * scale), true)) + { + if (child) + { + UiSharedService.ColorText("Other file types", UIColors.Get("LightlessPurple")); + ImGuiHelpers.ScaledDummy(4); + + using var tabBar = ImRaii.TabBar("otherFileTabs", ImGuiTabBarFlags.NoCloseWithMiddleMouseButton); + foreach (var fileGroup in otherFileGroups) + { + string tabLabel = $"{fileGroup.Key} [{fileGroup.Count()}]"; + var requiresCompute = fileGroup.Any(k => !k.IsComputed); + using var tabCol = ImRaii.PushColor(ImGuiCol.Tab, UiSharedService.Color(UIColors.Get("LightlessYellow")), requiresCompute); + if (requiresCompute) + { + tabLabel += " (!)"; + } + + ImRaii.IEndObject tabItem; + using (var textCol = ImRaii.PushColor(ImGuiCol.Text, UiSharedService.Color(new Vector4(0, 0, 0, 1)), + requiresCompute && !string.Equals(_selectedFileTypeTab, fileGroup.Key, StringComparison.Ordinal))) + { + tabItem = ImRaii.TabItem(tabLabel + "###other_" + fileGroup.Key); + } + + if (!tabItem) + { + tabItem.Dispose(); + continue; + } + + activeGroup = fileGroup; + + if (!string.Equals(_selectedFileTypeTab, fileGroup.Key, StringComparison.Ordinal)) + { + _selectedFileTypeTab = fileGroup.Key; + _selectedHash = string.Empty; + } + + var originalTotal = fileGroup.Sum(c => c.OriginalSize); + var compressedTotal = fileGroup.Sum(c => c.CompressedSize); + + var badgeBg = new Vector4(accent.X, accent.Y, accent.Z, 0.18f); + var badgeBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.35f); + var summaryHeight = MathF.Max(ImGui.GetTextLineHeightWithSpacing() * 2.6f, 36f * scale); + var summaryWidth = MathF.Min(420f * scale, ImGui.GetContentRegionAvail().X); + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 4f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(badgeBg))) + using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(badgeBorder))) + using (var summaryChild = ImRaii.Child($"otherFileSummary##{fileGroup.Key}", new Vector2(summaryWidth, summaryHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) + { + if (summaryChild) + { + var infoColor = ImGuiColors.DalamudGrey; + var countColor = UIColors.Get("LightlessBlue"); + var actualColor = ImGuiColors.DalamudGrey; + var compressedColor = UIColors.Get("LightlessYellow2"); + + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(10f * scale, 4f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(12f * scale, 2f * scale))) + { + using var summaryTable = ImRaii.Table("otherFileSummaryTable", 3, + ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.PadOuterX | ImGuiTableFlags.NoHostExtendX, + new Vector2(-1f, -1f)); + if (summaryTable) + { + ImGui.TableNextRow(); + DrawSummaryCell(FontAwesomeIcon.LayerGroup, countColor, + fileGroup.Count().ToString("N0", CultureInfo.InvariantCulture), + $"{fileGroup.Key} files", infoColor, scale); + DrawSummaryCell(FontAwesomeIcon.FileArchive, actualColor, + UiSharedService.ByteToString(originalTotal), + "Actual size", infoColor, scale); + DrawSummaryCell(FontAwesomeIcon.CompressArrowsAlt, compressedColor, + UiSharedService.ByteToString(compressedTotal), + "Compressed size", infoColor, scale); + } + } + } + } + + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(18f * scale, 4f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.FramePadding, new Vector2(4f * scale, 3f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 3f * scale))) + { + DrawTable(fileGroup); + } + + tabItem.Dispose(); + } + } + } + + if (activeGroup == null && otherFileGroups.Count > 0) + { + activeGroup = otherFileGroups[0]; + } + + DrawSelectedFileDetails(activeGroup); + } + + private void DrawSelectedFileDetails(IGrouping? fileGroup) + { + var hasGroup = fileGroup != null; + var selectionInGroup = hasGroup && !string.IsNullOrEmpty(_selectedHash) && + fileGroup!.Any(entry => string.Equals(entry.Hash, _selectedHash, StringComparison.Ordinal)); + + var scale = ImGuiHelpers.GlobalScale; + var accent = UIColors.Get("LightlessBlue"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.12f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.3f); + + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 5f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(10f * scale, 6f * scale))) + using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(accentBg))) + using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(accentBorder))) + using (var child = ImRaii.Child("selectedFileDetails", new Vector2(-1f, SelectedFilePanelLogicalHeight * scale), true)) + { + if (!child) + { + return; + } + + if (!selectionInGroup || + _cachedAnalysis == null || + !_cachedAnalysis.TryGetValue(_selectedObjectTab, out var objectEntries) || + !objectEntries.TryGetValue(_selectedHash, out var item)) + { + UiSharedService.ColorText("Select a file row to view details.", ImGuiColors.DalamudGrey); + return; + } + + UiSharedService.ColorText("Selected file:", UIColors.Get("LightlessBlue")); + ImGui.SameLine(); + UiSharedService.ColorText(_selectedHash, UIColors.Get("LightlessYellow")); + + ImGuiHelpers.ScaledDummy(2); + + UiSharedService.ColorText("Local file path:", UIColors.Get("LightlessBlue")); + ImGui.SameLine(); + UiSharedService.TextWrapped(item.FilePaths[0]); + if (item.FilePaths.Count > 1) + { + ImGui.SameLine(); + ImGui.TextUnformatted($"(and {item.FilePaths.Count - 1} more)"); + ImGui.SameLine(); + _uiSharedService.IconText(FontAwesomeIcon.InfoCircle); + UiSharedService.AttachToolTip(string.Join(Environment.NewLine, item.FilePaths.Skip(1))); + } + + UiSharedService.ColorText("Used by game path:", UIColors.Get("LightlessBlue")); + ImGui.SameLine(); + UiSharedService.TextWrapped(item.GamePaths[0]); + if (item.GamePaths.Count > 1) + { + ImGui.SameLine(); + ImGui.TextUnformatted($"(and {item.GamePaths.Count - 1} more)"); + ImGui.SameLine(); + _uiSharedService.IconText(FontAwesomeIcon.InfoCircle); + UiSharedService.AttachToolTip(string.Join(Environment.NewLine, item.GamePaths.Skip(1))); + } + } + } + + private TextureRow? DrawTextureTable(IReadOnlyList rows, long totalOriginal, long totalCompressed, bool hasAnyTextureRows) + { + var scale = ImGuiHelpers.GlobalScale; + if (rows.Count > 0) + { + var accent = UIColors.Get("LightlessBlue"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.14f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.35f); + var originalColor = ImGuiColors.DalamudGrey; + var compressedColor = UIColors.Get("LightlessYellow2"); + var infoColor = ImGuiColors.DalamudGrey; + var countLabel = rows.Count == 1 ? "Matching texture" : "Matching textures"; + var diff = totalOriginal - totalCompressed; + var diffMagnitude = Math.Abs(diff); + var diffColor = diff > 0 ? UIColors.Get("LightlessGreen") + : diff < 0 ? UIColors.Get("DimRed") + : ImGuiColors.DalamudGrey; + var diffLabel = diff > 0 ? "Saved" : diff < 0 ? "Overhead" : "Lossless"; + var diffPercent = diffMagnitude > 0 && totalOriginal > 0 + ? ((diffMagnitude * 100d) / totalOriginal).ToString("0", CultureInfo.InvariantCulture) + "%" + : null; + + using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 6f * scale)) + using (ImRaii.PushStyle(ImGuiStyleVar.ChildBorderSize, MathF.Max(1f, ImGui.GetStyle().ChildBorderSize))) + using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(12f * scale, 6f * scale))) + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(18f * scale, 4f * scale))) + using (ImRaii.PushColor(ImGuiCol.ChildBg, UiSharedService.Color(accentBg))) + using (ImRaii.PushColor(ImGuiCol.Border, UiSharedService.Color(accentBorder))) + { + var lineHeight = ImGui.GetTextLineHeightWithSpacing(); + var summaryHeight = MathF.Max(lineHeight * 2.4f, ImGui.GetFrameHeightWithSpacing() * 2.2f); + using (var summary = ImRaii.Child("textureCompressionSummary", new Vector2(-1f, summaryHeight), true, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) + { + if (summary) + { + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(8f * scale, 4f * scale))) + { + if (ImGui.BeginTable("textureCompressionSummaryTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.PadOuterX | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.NoHostExtendX)) + { + ImGui.TableNextRow(); + DrawSummaryStat(FontAwesomeIcon.Images, accent, $"{rows.Count:N0}", countLabel, infoColor); + DrawSummaryStat(FontAwesomeIcon.FileArchive, originalColor, UiSharedService.ByteToString(totalOriginal), "Original total", infoColor); + DrawSummaryStat(FontAwesomeIcon.CompressArrowsAlt, compressedColor, UiSharedService.ByteToString(totalCompressed), "Compressed total", infoColor); + DrawSummaryStat( + FontAwesomeIcon.ChartLine, + diffColor, + diffMagnitude > 0 ? UiSharedService.ByteToString(diffMagnitude) : "No change", + diffLabel, + diffColor, + diffPercent, + diffColor); + + ImGui.EndTable(); + } + } + } + } + } + } + else + { + if (hasAnyTextureRows) + { + UiSharedService.TextWrapped("No textures match the current filters. Try clearing filters or refreshing the analysis session."); + } + else + { + UiSharedService.ColorText("No textures recorded for this object.", ImGuiColors.DalamudGrey); + } + } + + UiSharedService.TextWrapped("Mark textures using the checkbox to add them to the compression queue. You can adjust the target format for each texture before starting the batch compression."); + + bool conversionRunning = _conversionTask != null && !_conversionTask.IsCompleted; + var activeSelectionCount = _textureRows.Count(row => _selectedTextureKeys.Contains(row.Key) && !row.IsAlreadyCompressed); + bool hasSelection = activeSelectionCount > 0; + using (ImRaii.Disabled(conversionRunning || !hasSelection)) + { + var label = hasSelection ? $"Compress {activeSelectionCount} selected" : "Compress selected"; + if (_uiSharedService.IconTextButton(FontAwesomeIcon.CompressArrowsAlt, label, 220f * scale)) + { + StartTextureConversion(); + } + } + ImGui.SameLine(); + using (ImRaii.Disabled(_selectedTextureKeys.Count == 0 && _textureSelections.Count == 0)) + { + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Broom, "Clear marks", 160f * scale)) + { + _selectedTextureKeys.Clear(); + _textureSelections.Clear(); + } + } + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Sync, "Refresh", 130f * scale)) + { + _textureRowsDirty = true; + } + + TextureRow? lastSelected = null; + using (var table = ImRaii.Table("textureDataTable", 9, + ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.Sortable, + new Vector2(-1, 0))) + { + if (table) + { + ImGui.TableSetupColumn("##select", ImGuiTableColumnFlags.WidthFixed | ImGuiTableColumnFlags.NoSort, 32f * scale); + ImGui.TableSetupColumn("Texture", ImGuiTableColumnFlags.WidthFixed | ImGuiTableColumnFlags.NoSort, 310f * scale); + ImGui.TableSetupColumn("Slot", ImGuiTableColumnFlags.NoSort); + ImGui.TableSetupColumn("Map", ImGuiTableColumnFlags.NoSort); + ImGui.TableSetupColumn("Format", ImGuiTableColumnFlags.NoSort); + ImGui.TableSetupColumn("Recommended", ImGuiTableColumnFlags.NoSort); + ImGui.TableSetupColumn("Target", ImGuiTableColumnFlags.WidthFixed | ImGuiTableColumnFlags.NoSort, 140f * scale); + ImGui.TableSetupColumn("Original", ImGuiTableColumnFlags.PreferSortDescending); + ImGui.TableSetupColumn("Compressed", ImGuiTableColumnFlags.PreferSortDescending); + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); + + var targets = _textureCompressionService.SelectableTargets; + + IEnumerable orderedRows = rows; + var sortSpecs = ImGui.TableGetSortSpecs(); + if (sortSpecs.SpecsCount > 0) + { + var spec = sortSpecs.Specs[0]; + orderedRows = spec.ColumnIndex switch + { + 7 => spec.SortDirection == ImGuiSortDirection.Ascending + ? rows.OrderBy(r => r.OriginalSize) + : rows.OrderByDescending(r => r.OriginalSize), + 8 => spec.SortDirection == ImGuiSortDirection.Ascending + ? rows.OrderBy(r => r.CompressedSize) + : rows.OrderByDescending(r => r.CompressedSize), + _ => rows + }; + + sortSpecs.SpecsDirty = false; + } + + var index = 0; + foreach (var row in orderedRows) + { + DrawTextureRow(row, targets, index); + index++; + } + } + } + + return rows.FirstOrDefault(r => r.Key == _selectedTextureKey); + + void DrawSummaryStat(FontAwesomeIcon icon, Vector4 iconColor, string mainText, string subText, Vector4 subColor, string? extraText = null, Vector4? extraColor = null) + { + ImGui.TableNextColumn(); + using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(6f * scale, 2f * scale))) + using (ImRaii.Group()) + { + _uiSharedService.IconText(icon, iconColor); + ImGui.SameLine(0f, 6f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, iconColor)) + { + ImGui.TextUnformatted(mainText); + } + using (ImRaii.PushColor(ImGuiCol.Text, subColor)) + { + ImGui.TextUnformatted(subText); + } + if (!string.IsNullOrWhiteSpace(extraText)) + { + ImGui.SameLine(0f, 6f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, extraColor ?? iconColor)) + { + ImGui.TextUnformatted(extraText); + } + } + } + } + } + private void StartTextureConversion() + { + if (_conversionTask != null && !_conversionTask.IsCompleted) + { + return; + } + + var selectedRows = _textureRows + .Where(row => _selectedTextureKeys.Contains(row.Key) && !row.IsAlreadyCompressed) + .ToList(); + if (selectedRows.Count == 0) + { + return; + } + + var requests = selectedRows.Select(row => + { + var desiredTarget = _textureSelections.TryGetValue(row.Key, out var selection) + ? selection + : row.SuggestedTarget ?? row.CurrentTarget ?? _textureCompressionService.DefaultTarget; + var normalizedTarget = _textureCompressionService.NormalizeTarget(desiredTarget); + _textureSelections[row.Key] = normalizedTarget; + + return new TextureCompressionRequest(row.PrimaryFilePath, row.DuplicateFilePaths, normalizedTarget); + }).ToList(); + + _conversionCancellationTokenSource = _conversionCancellationTokenSource.CancelRecreate(); + _conversionTotalJobs = requests.Count; + _lastConversionProgress = null; + _conversionCurrentFileName = string.Empty; + _conversionCurrentFileProgress = 0; + _conversionFailed = false; + + _conversionTask = RunTextureConversionAsync(requests, _conversionCancellationTokenSource.Token); + _showModal = true; + } + + private async Task RunTextureConversionAsync(List requests, CancellationToken token) + { + try + { + await _textureCompressionService.ConvertTexturesAsync(requests, _conversionProgress, token).ConfigureAwait(false); + + if (!token.IsCancellationRequested) + { + var affectedPaths = requests + .SelectMany(static request => + { + IEnumerable paths = request.DuplicateFilePaths; + return new[] { request.PrimaryFilePath }.Concat(paths); + }) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + if (affectedPaths.Count > 0) + { + try + { + await _characterAnalyzer.UpdateFileEntriesAsync(affectedPaths, token).ConfigureAwait(false); + _hasUpdate = true; + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception updateEx) + { + _logger.LogWarning(updateEx, "Failed to refresh compressed size data after texture conversion."); + } + } + } + } + catch (OperationCanceledException) + { + _logger.LogInformation("Texture compression was cancelled."); + } + catch (Exception ex) + { + _conversionFailed = true; + _logger.LogError(ex, "Texture compression failed."); + } + finally + { + _selectedTextureKeys.Clear(); + _textureSelections.Clear(); + _textureRowsDirty = true; + } + } + + private void DrawVerticalResizeHandle(string id, float topY, float height, ref float leftWidth, float minWidth, float maxWidth, bool invert = false) + { + var scale = ImGuiHelpers.GlobalScale; + var splitterWidth = 8f * scale; + ImGui.SameLine(); + var cursor = ImGui.GetCursorPos(); + ImGui.SetCursorPos(new Vector2(cursor.X, topY)); + ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("ButtonDefault")); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessPurple")); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessPurpleActive")); + ImGui.Button(id, new Vector2(splitterWidth, height)); + ImGui.PopStyleColor(3); + + if (ImGui.IsItemActive()) + { + var delta = ImGui.GetIO().MouseDelta.X / scale; + leftWidth += invert ? -delta : delta; + leftWidth = Math.Clamp(leftWidth, minWidth, maxWidth); + } + ImGui.SetCursorPos(new Vector2(cursor.X + splitterWidth + ImGui.GetStyle().ItemSpacing.X, cursor.Y)); + } + + private (IDalamudTextureWrap? Texture, bool IsLoading, string? Error) GetTexturePreview(TextureRow row) + { + var key = row.Key; + if (!_texturePreviews.TryGetValue(key, out var state)) + { + state = new TexturePreviewState(); + _texturePreviews[key] = state; + } + + state.LastAccessUtc = DateTime.UtcNow; + + if (state.Texture != null) + { + return (state.Texture, false, state.ErrorMessage); + } + + if (state.LoadTask == null) + { + state.LoadTask = Task.Run(async () => + { + try + { + var texture = await BuildPreviewAsync(row, CancellationToken.None).ConfigureAwait(false); + state.Texture = texture; + state.ErrorMessage = texture == null ? "Preview unavailable." : null; + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to load preview for {File}", row.PrimaryFilePath); + state.ErrorMessage = "Failed to load preview."; + } + }); + } + + if (state.LoadTask.IsCompleted) + { + state.LoadTask = null; + return (state.Texture, false, state.ErrorMessage); + } + + return (null, true, state.ErrorMessage); + } + + private async Task BuildPreviewAsync(TextureRow row, CancellationToken token) + { + if (!_ipcManager.Penumbra.APIAvailable) + { + return null; + } + + var tempFile = Path.Combine(Path.GetTempPath(), $"lightless_preview_{Guid.NewGuid():N}.png"); + try + { + var job = new TextureConversionJob(row.PrimaryFilePath, tempFile, TextureType.Png, IncludeMipMaps: false); + await _ipcManager.Penumbra.ConvertTextureFiles(_logger, new[] { job }, null, token).ConfigureAwait(false); + if (!File.Exists(tempFile)) + { + return null; + } + + var data = await File.ReadAllBytesAsync(tempFile, token).ConfigureAwait(false); + return _uiSharedService.LoadImage(data); + } + catch (OperationCanceledException) + { + return null; + } + catch (Exception ex) + { + _logger.LogDebug(ex, "Preview generation failed for {File}", row.PrimaryFilePath); + return null; + } + finally + { + try + { + if (File.Exists(tempFile)) + { + File.Delete(tempFile); + } + } + catch (Exception ex) + { + _logger.LogTrace(ex, "Failed to clean up preview temp file {File}", tempFile); + } + } + } + + private void ResetPreview(string key) + { + if (_texturePreviews.TryGetValue(key, out var state)) + { + state.Texture?.Dispose(); + _texturePreviews.Remove(key); + } + } + + private void DrawTextureRow(TextureRow row, IReadOnlyList targets, int index) + { + var key = row.Key; + bool isSelected = string.Equals(_selectedTextureKey, key, StringComparison.Ordinal); + + ImGui.TableNextRow(ImGuiTableRowFlags.None, 0); + ApplyTextureRowBackground(row, isSelected); + + bool canCompress = !row.IsAlreadyCompressed; + if (!canCompress) + { + _selectedTextureKeys.Remove(key); + _textureSelections.Remove(key); + } + + ImGui.TableNextColumn(); + if (canCompress) + { + bool marked = _selectedTextureKeys.Contains(key); + if (UiSharedService.CheckboxWithBorder($"##select{index}", ref marked, UIColors.Get("LightlessPurple"), 1.5f)) + { + if (marked) + { + _selectedTextureKeys.Add(key); + } + else + { + _selectedTextureKeys.Remove(key); + } + } + UiSharedService.AttachToolTip("Mark texture for batch compression."); + } + else + { + ImGui.TextDisabled("-"); + UiSharedService.AttachToolTip("Already stored in a compressed format; additional compression is disabled."); + } + + DrawSelectableColumn(isSelected, () => + { + var selectableLabel = $"{row.DisplayName}##texName{index}"; + if (ImGui.Selectable(selectableLabel, isSelected)) + { + _selectedTextureKey = isSelected ? string.Empty : key; + } + + return () => UiSharedService.AttachToolTip($"{row.PrimaryFilePath}{UiSharedService.TooltipSeparator}{string.Join(Environment.NewLine, row.GamePaths)}"); + }); + + DrawSelectableColumn(isSelected, () => + { + ImGui.TextUnformatted(row.Slot); + return null; + }); + DrawSelectableColumn(isSelected, () => + { + ImGui.TextUnformatted(row.MapKind.ToString()); + return null; + }); + DrawSelectableColumn(isSelected, () => + { + ImGui.TextUnformatted(row.Format); + return null; + }); + + DrawSelectableColumn(isSelected, () => + { + if (row.SuggestedTarget.HasValue) + { + ImGui.TextUnformatted(row.SuggestedTarget.Value.ToString()); + if (!string.IsNullOrEmpty(row.SuggestionReason)) + { + var reason = row.SuggestionReason; + return () => UiSharedService.AttachToolTip(reason); + } + } + else + { + ImGui.TextUnformatted("-"); + } + + return null; + }); + + ImGui.TableNextColumn(); + if (canCompress) + { + var desiredTarget = _textureSelections.TryGetValue(key, out var storedTarget) + ? storedTarget + : row.SuggestedTarget ?? row.CurrentTarget ?? _textureCompressionService.DefaultTarget; + var currentSelection = _textureCompressionService.NormalizeTarget(desiredTarget); + if (!_textureSelections.TryGetValue(key, out _) || storedTarget != currentSelection) + { + _textureSelections[key] = currentSelection; + } + var comboLabel = currentSelection.ToString(); + ImGui.SetNextItemWidth(-1); + if (ImGui.BeginCombo($"##target{index}", comboLabel)) + { + foreach (var target in targets) + { + bool targetSelected = currentSelection == target; + if (ImGui.Selectable(target.ToString(), targetSelected)) + { + _textureSelections[key] = target; + currentSelection = target; + } + if (targetSelected) + { + ImGui.SetItemDefaultFocus(); + } + } + + ImGui.EndCombo(); + } + } + else + { + var label = row.CurrentTarget?.ToString() ?? row.Format; + ImGui.TextUnformatted(label); + UiSharedService.AttachToolTip("This texture is already compressed and cannot be processed again."); + } + + DrawSelectableColumn(isSelected, () => + { + ImGui.TextUnformatted(UiSharedService.ByteToString(row.OriginalSize)); + return null; + }); + DrawSelectableColumn(isSelected, () => + { + ImGui.TextUnformatted(UiSharedService.ByteToString(row.CompressedSize)); + return null; + }); + } + + private static void DrawSelectableColumn(bool isSelected, Func draw) + { + ImGui.TableNextColumn(); + if (isSelected) + { + ImGui.PushStyleColor(ImGuiCol.Text, SelectedTextureRowTextColor); + } + + var after = draw(); + + if (isSelected) + { + ImGui.PopStyleColor(); + } + + after?.Invoke(); + } + + private static void ApplyTextureRowBackground(TextureRow row, bool isSelected) + { + if (isSelected) + { + var highlight = UiSharedService.Color(UIColors.Get("LightlessYellow")); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, highlight); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, highlight); + } + else if (row.IsAlreadyCompressed) + { + var compressedColor = UiSharedService.Color(UIColors.Get("LightlessGreenDefault")); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, compressedColor); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, compressedColor); + } + else if (!row.IsComputed) + { + var warning = UiSharedService.Color(UIColors.Get("DimRed")); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, warning); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, warning); + } + } + + private void DrawTextureDetail(TextureRow? row) + { + var scale = ImGuiHelpers.GlobalScale; + + UiSharedService.ColorText("Texture Details", UIColors.Get("LightlessPurple")); + if (row != null) + { + ImGui.SameLine(); + ImGui.TextUnformatted(row.DisplayName); + UiSharedService.AttachToolTip("Source file: " + row.PrimaryFilePath); + } + ImGui.Separator(); + + if (row == null) + { + UiSharedService.ColorText("Select a texture to view details.", ImGuiColors.DalamudGrey); + return; + } + + var (previewTexture, previewLoading, previewError) = GetTexturePreview(row); + var previewSize = new Vector2(_texturePreviewSize * 0.85f, _texturePreviewSize * 0.85f) * scale; + + if (previewTexture != null) + { + ImGui.Image(previewTexture.Handle, previewSize); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.SyncAlt, "Refresh preview", 180f * ImGuiHelpers.GlobalScale)) + { + ResetPreview(row.Key); + } + } + else + { + using (ImRaii.Child("previewPlaceholder", previewSize, true)) + { + UiSharedService.TextWrapped(previewLoading ? "Generating preview..." : previewError ?? "Preview unavailable."); + } + if (!previewLoading && _uiSharedService.IconTextButton(FontAwesomeIcon.SyncAlt, "Retry preview", 180f * ImGuiHelpers.GlobalScale)) + { + ResetPreview(row.Key); + } + } + + var desiredDetailTarget = _textureSelections.TryGetValue(row.Key, out var userTarget) + ? userTarget + : row.SuggestedTarget ?? row.CurrentTarget ?? _textureCompressionService.DefaultTarget; + var selectedTarget = _textureCompressionService.NormalizeTarget(desiredDetailTarget); + if (!_textureSelections.TryGetValue(row.Key, out _) || userTarget != selectedTarget) + { + _textureSelections[row.Key] = selectedTarget; + } + var hasSelectedInfo = _textureMetadataHelper.TryGetRecommendationInfo(selectedTarget, out var selectedInfo); + + using (ImRaii.Child("textureDetailInfo", new Vector2(-1, 0), true, ImGuiWindowFlags.AlwaysVerticalScrollbar)) + { + using var detailSpacing = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(6f * scale, 2f * scale)); + DrawMetaOverview(); + + ImGuiHelpers.ScaledDummy(4); + DrawSizeSummary(); + + ImGuiHelpers.ScaledDummy(4); + DrawCompressionInsights(); + + ImGuiHelpers.ScaledDummy(6); + DrawExpandableList("Duplicate Files", row.DuplicateFilePaths, "No duplicate files detected."); + DrawExpandableList("Game Paths", row.GamePaths, "No game paths recorded."); + } + + void DrawMetaOverview() + { + var labelColor = ImGuiColors.DalamudGrey; + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(5f * scale, 2f * scale))) + { + var metaFlags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.PadOuterX; + if (ImGui.BeginTable("textureMetaOverview", 2, metaFlags)) + { + MetaRow(FontAwesomeIcon.Cube, "Object", row.ObjectKind.ToString()); + MetaRow(FontAwesomeIcon.Tag, "Slot", row.Slot); + MetaRow(FontAwesomeIcon.LayerGroup, "Map Type", row.MapKind.ToString()); + MetaRow(FontAwesomeIcon.Fingerprint, "Hash", row.Hash, UIColors.Get("LightlessBlue")); + MetaRow(FontAwesomeIcon.InfoCircle, "Current Format", row.Format); + + var selectedLabel = hasSelectedInfo ? selectedInfo!.Title : selectedTarget.ToString(); + var selectionColor = hasSelectedInfo ? UIColors.Get("LightlessYellow") : UIColors.Get("LightlessGreen"); + MetaRow(FontAwesomeIcon.Bullseye, "Selected Target", selectedLabel, selectionColor); + + ImGui.EndTable(); + } + } + + void MetaRow(FontAwesomeIcon icon, string label, string value, Vector4? valueColor = null) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + _uiSharedService.IconText(icon, labelColor); + ImGui.SameLine(0f, 4f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, labelColor)) + { + ImGui.TextUnformatted(label); + } + + ImGui.TableNextColumn(); + if (valueColor.HasValue) + { + using (ImRaii.PushColor(ImGuiCol.Text, valueColor.Value)) + { + ImGui.TextUnformatted(value); + } + } + else + { + ImGui.TextUnformatted(value); + } + } + } + + void DrawSizeSummary() + { + var savedBytes = row.OriginalSize - row.CompressedSize; + var savedMagnitude = Math.Abs(savedBytes); + var savedColor = savedBytes > 0 ? UIColors.Get("LightlessGreen") : savedBytes < 0 ? UIColors.Get("DimRed") : ImGuiColors.DalamudGrey; + var savedLabel = savedBytes > 0 ? "Saved" : savedBytes < 0 ? "Over" : "Delta"; + var savedPercent = row.OriginalSize > 0 && savedMagnitude > 0 + ? $"{savedMagnitude * 100d / row.OriginalSize:0.#}%" + : null; + + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 2f * scale))) + { + var statFlags = ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.PadOuterX; + if (ImGui.BeginTable("textureSizeSummary", 3, statFlags)) + { + ImGui.TableNextRow(); + StatCell(FontAwesomeIcon.Database, ImGuiColors.DalamudGrey, UiSharedService.ByteToString(row.OriginalSize), "Original"); + StatCell(FontAwesomeIcon.CompressArrowsAlt, UIColors.Get("LightlessYellow2"), UiSharedService.ByteToString(row.CompressedSize), "Compressed"); + StatCell(FontAwesomeIcon.ChartLine, savedColor, savedMagnitude > 0 ? UiSharedService.ByteToString(savedMagnitude) : "No change", savedLabel, savedPercent, savedColor); + ImGui.EndTable(); + } + } + + void StatCell(FontAwesomeIcon icon, Vector4 iconColor, string mainText, string caption, string? extra = null, Vector4? extraColor = null) + { + ImGui.TableNextColumn(); + _uiSharedService.IconText(icon, iconColor); + ImGui.SameLine(0f, 4f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, iconColor)) + { + ImGui.TextUnformatted(mainText); + } + using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudGrey)) + { + ImGui.TextUnformatted(caption); + } + if (!string.IsNullOrEmpty(extra)) + { + ImGui.SameLine(0f, 4f * scale); + using (ImRaii.PushColor(ImGuiCol.Text, extraColor ?? iconColor)) + { + ImGui.TextUnformatted(extra); + } + } + } + } + + void DrawCompressionInsights() + { + var matchesRecommendation = row.SuggestedTarget.HasValue && row.SuggestedTarget.Value == selectedTarget; + var columnCount = row.SuggestedTarget.HasValue ? 2 : 1; + using (ImRaii.PushStyle(ImGuiStyleVar.CellPadding, new Vector2(6f * scale, 2f * scale))) + { + var cardFlags = ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.NoBordersInBody | ImGuiTableFlags.PadOuterX; + if (ImGui.BeginTable("textureCompressionCards", columnCount, cardFlags)) + { + ImGui.TableNextRow(); + var selectedTitleColor = matchesRecommendation ? UIColors.Get("LightlessGreen") : UIColors.Get("LightlessBlue"); + var selectedDescription = hasSelectedInfo + ? selectedInfo!.Description + : matchesRecommendation + ? "Selected target matches the automatic recommendation." + : "Manual selection without additional guidance."; + DrawCompressionCard("Selected Target", selectedLabelText(), selectedTitleColor, selectedDescription); + + if (row.SuggestedTarget.HasValue) + { + var recommendedTarget = row.SuggestedTarget.Value; + var hasRecommendationInfo = _textureMetadataHelper.TryGetRecommendationInfo(recommendedTarget, out var recommendedInfo); + var recommendedTitle = hasRecommendationInfo ? recommendedInfo!.Title : recommendedTarget.ToString(); + var recommendedDescription = hasRecommendationInfo + ? recommendedInfo!.Description + : string.IsNullOrEmpty(row.SuggestionReason) ? "No additional context provided." : row.SuggestionReason; + + DrawCompressionCard("Recommended Target", recommendedTitle, UIColors.Get("LightlessYellow"), recommendedDescription); + } + + ImGui.EndTable(); + } + } + + using (ImRaii.PushIndent(12f * scale)) + { + if (!row.SuggestedTarget.HasValue) + { + UiSharedService.ColorTextWrapped("No automatic recommendation available.", UIColors.Get("LightlessYellow")); + } + + if (!matchesRecommendation && row.SuggestedTarget.HasValue) + { + UiSharedService.ColorTextWrapped("Selected compression differs from the recommendation. Review before running batch conversion.", UIColors.Get("DimRed")); + } + } + + string selectedLabelText() + { + if (hasSelectedInfo) + { + return selectedInfo!.Title; + } + + return selectedTarget.ToString(); + } + + void DrawCompressionCard(string header, string title, Vector4 titleColor, string body) + { + ImGui.TableNextColumn(); + UiSharedService.ColorText(header, UIColors.Get("LightlessPurple")); + using (ImRaii.PushColor(ImGuiCol.Text, titleColor)) + { + ImGui.TextUnformatted(title); + } + UiSharedService.TextWrapped(body, 0, ImGuiColors.DalamudGrey); + } + } + + void DrawExpandableList(string title, IReadOnlyList entries, string emptyMessage) + { + _ = emptyMessage; + var count = entries.Count; + using var headerDefault = ImRaii.PushColor(ImGuiCol.Header, UiSharedService.Color(new Vector4(0.15f, 0.15f, 0.18f, 0.95f))); + using var headerHover = ImRaii.PushColor(ImGuiCol.HeaderHovered, UiSharedService.Color(new Vector4(0.2f, 0.2f, 0.25f, 1f))); + using var headerActive = ImRaii.PushColor(ImGuiCol.HeaderActive, UiSharedService.Color(new Vector4(0.25f, 0.25f, 0.3f, 1f))); + var label = $"{title} ({count})"; + if (!ImGui.CollapsingHeader(label, count == 0 ? ImGuiTreeNodeFlags.Leaf : ImGuiTreeNodeFlags.None)) + { + return; + } + + if (count == 0) + { + return; + } + + var tableFlags = ImGuiTableFlags.PadOuterX | ImGuiTableFlags.NoHostExtendX | ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInnerV | ImGuiTableFlags.BordersOuter; + if (ImGui.BeginTable($"{title}Table", 2, tableFlags)) + { + ImGui.TableSetupColumn("#", ImGuiTableColumnFlags.WidthFixed, 28f * scale); + ImGui.TableSetupColumn("Path", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableHeadersRow(); + + for (int i = 0; i < entries.Count; i++) + { + ImGui.TableNextRow(); + ImGui.TableNextColumn(); + ImGui.TextUnformatted($"{i + 1}."); + + ImGui.TableNextColumn(); + var wrapPos = ImGui.GetCursorPosX() + ImGui.GetColumnWidth(); + ImGui.PushTextWrapPos(wrapPos); + ImGui.TextUnformatted(entries[i]); + ImGui.PopTextWrapPos(); + } + + ImGui.EndTable(); + } + } + } + + private void SortCachedAnalysis( + ObjectKind objectKind, + Func, TKey> selector, + bool ascending, + IComparer? comparer = null) + { + if (_cachedAnalysis == null || !_cachedAnalysis.TryGetValue(objectKind, out var current)) + { + return; + } + + var ordered = ascending + ? (comparer != null ? current.OrderBy(selector, comparer) : current.OrderBy(selector)) + : (comparer != null ? current.OrderByDescending(selector, comparer) : current.OrderByDescending(selector)); + + _cachedAnalysis[objectKind] = ordered.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal); } private void DrawTable(IGrouping fileGroup) { - var tableColumns = string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal) - ? (_enableBc7ConversionMode ? 7 : 6) - : (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) ? 6 : 5); - using var table = ImRaii.Table("Analysis", tableColumns, ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingFixedFit, - new Vector2(0, 300)); - if (!table.Success) return; + var tableColumns = string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) ? 6 : 5; + var scale = ImGuiHelpers.GlobalScale; + using var table = ImRaii.Table("Analysis", tableColumns, + ImGuiTableFlags.Sortable | ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollY | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.BordersOuter | ImGuiTableFlags.BordersInnerV, + new Vector2(-1f, 0f)); + if (!table.Success) + { + return; + } + ImGui.TableSetupColumn("Hash"); ImGui.TableSetupColumn("Filepaths"); ImGui.TableSetupColumn("Gamepaths"); ImGui.TableSetupColumn("Original Size"); ImGui.TableSetupColumn("Compressed Size"); - if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal)) - { - ImGui.TableSetupColumn("Format"); - if (_enableBc7ConversionMode) ImGui.TableSetupColumn("Convert to BC7"); - } if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal)) { ImGui.TableSetupColumn("Triangles"); } + ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableHeadersRow(); var sortSpecs = ImGui.TableGetSortSpecs(); - if (sortSpecs.SpecsDirty) + if (sortSpecs.SpecsDirty && sortSpecs.SpecsCount > 0) { - var idx = sortSpecs.Specs.ColumnIndex; + var spec = sortSpecs.Specs[0]; + bool ascending = spec.SortDirection == ImGuiSortDirection.Ascending; - if (idx == 0 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Key, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 0 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Key, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 1 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.FilePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 1 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.FilePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 2 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.GamePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 2 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.GamePaths.Count).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 3 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.OriginalSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 3 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.OriginalSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 4 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.CompressedSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (idx == 4 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.CompressedSize).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.Triangles).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.Triangles).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Ascending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderBy(k => k.Value.Format.Value, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); - if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal) && idx == 5 && sortSpecs.Specs.SortDirection == ImGuiSortDirection.Descending) - _cachedAnalysis![_selectedObjectTab] = _cachedAnalysis[_selectedObjectTab].OrderByDescending(k => k.Value.Format.Value, StringComparer.Ordinal).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal); + switch (spec.ColumnIndex) + { + case 0: + SortCachedAnalysis(_selectedObjectTab, pair => pair.Key, ascending, StringComparer.Ordinal); + break; + case 1: + SortCachedAnalysis(_selectedObjectTab, pair => pair.Value.FilePaths.Count, ascending); + break; + case 2: + SortCachedAnalysis(_selectedObjectTab, pair => pair.Value.GamePaths.Count, ascending); + break; + case 3: + SortCachedAnalysis(_selectedObjectTab, pair => pair.Value.OriginalSize, ascending); + break; + case 4: + SortCachedAnalysis(_selectedObjectTab, pair => pair.Value.CompressedSize, ascending); + break; + case 5 when string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal): + SortCachedAnalysis(_selectedObjectTab, pair => pair.Value.Triangles, ascending); + break; + } sortSpecs.SpecsDirty = false; } foreach (var item in fileGroup) { - using var text = ImRaii.PushColor(ImGuiCol.Text, new Vector4(0, 0, 0, 1), string.Equals(item.Hash, _selectedHash, StringComparison.Ordinal)); - using var text2 = ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 1, 1, 1), !item.IsComputed); + using var textColor = ImRaii.PushColor(ImGuiCol.Text, new Vector4(0, 0, 0, 1), string.Equals(item.Hash, _selectedHash, StringComparison.Ordinal)); + using var missingColor = ImRaii.PushColor(ImGuiCol.Text, new Vector4(1, 1, 1, 1), !item.IsComputed); ImGui.TableNextColumn(); if (!item.IsComputed) { - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, UiSharedService.Color(ImGuiColors.DalamudRed)); - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, UiSharedService.Color(ImGuiColors.DalamudRed)); + var warning = UiSharedService.Color(UIColors.Get("DimRed")); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, warning); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, warning); } if (string.Equals(_selectedHash, item.Hash, StringComparison.Ordinal)) { - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, UiSharedService.Color(UIColors.Get("LightlessYellow"))); - ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, UiSharedService.Color(UIColors.Get("LightlessYellow"))); + var highlight = UiSharedService.Color(UIColors.Get("LightlessYellow")); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg1, highlight); + ImGui.TableSetBgColor(ImGuiTableBgTarget.RowBg0, highlight); } ImGui.TextUnformatted(item.Hash); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; + if (ImGui.IsItemClicked()) + { + _selectedHash = string.Equals(_selectedHash, item.Hash, StringComparison.Ordinal) + ? string.Empty + : item.Hash; + } + ImGui.TableNextColumn(); ImGui.TextUnformatted(item.FilePaths.Count.ToString()); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; + ImGui.TableNextColumn(); ImGui.TextUnformatted(item.GamePaths.Count.ToString()); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; + ImGui.TableNextColumn(); ImGui.TextUnformatted(UiSharedService.ByteToString(item.OriginalSize)); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; + ImGui.TableNextColumn(); ImGui.TextUnformatted(UiSharedService.ByteToString(item.CompressedSize)); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; - if (string.Equals(fileGroup.Key, "tex", StringComparison.Ordinal)) - { - ImGui.TableNextColumn(); - ImGui.TextUnformatted(item.Format.Value); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; - if (_enableBc7ConversionMode) - { - ImGui.TableNextColumn(); - if (string.Equals(item.Format.Value, "BC7", StringComparison.Ordinal)) - { - ImGui.TextUnformatted(""); - continue; - } - var filePath = item.FilePaths[0]; - bool toConvert = _texturesToConvert.ContainsKey(filePath); - if (UiSharedService.CheckboxWithBorder("###convert" + item.Hash, ref toConvert, UIColors.Get("LightlessPurple"), 1.5f)) - { - if (toConvert && !_texturesToConvert.ContainsKey(filePath)) - { - _texturesToConvert[filePath] = item.FilePaths.Skip(1).ToArray(); - } - else if (!toConvert && _texturesToConvert.ContainsKey(filePath)) - { - _texturesToConvert.Remove(filePath); - } - } - } - } + if (string.Equals(fileGroup.Key, "mdl", StringComparison.Ordinal)) { ImGui.TableNextColumn(); ImGui.TextUnformatted(item.Triangles.ToString()); - if (ImGui.IsItemClicked()) _selectedHash = item.Hash; } } } diff --git a/LightlessSync/UI/DrawEntityFactory.cs b/LightlessSync/UI/DrawEntityFactory.cs index d1410ad..1ecf3f5 100644 --- a/LightlessSync/UI/DrawEntityFactory.cs +++ b/LightlessSync/UI/DrawEntityFactory.cs @@ -1,14 +1,21 @@ -using LightlessSync.API.Dto.Group; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using LightlessSync.API.Data.Extensions; +using LightlessSync.API.Dto.Group; using LightlessSync.LightlessConfiguration; +using LightlessSync.PlayerData.Factories; +using LightlessSync.PlayerData.Pairs; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; using LightlessSync.UI.Components; using LightlessSync.UI.Handlers; +using LightlessSync.UI.Models; using LightlessSync.WebAPI; using Microsoft.Extensions.Logging; -using System.Collections.Immutable; namespace LightlessSync.UI; @@ -19,6 +26,7 @@ public class DrawEntityFactory private readonly LightlessMediator _mediator; private readonly SelectPairForTagUi _selectPairForTagUi; private readonly ServerConfigurationManager _serverConfigurationManager; + private readonly LightlessConfigService _configService; private readonly UiSharedService _uiSharedService; private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private readonly CharaDataManager _charaDataManager; @@ -29,13 +37,28 @@ public class DrawEntityFactory private readonly SelectSyncshellForTagUi _selectSyncshellForTagUi; private readonly TagHandler _tagHandler; private readonly IdDisplayHandler _uidDisplayHandler; + private readonly PairLedger _pairLedger; + private readonly PairFactory _pairFactory; - public DrawEntityFactory(ILogger logger, ApiController apiController, IdDisplayHandler uidDisplayHandler, - SelectTagForPairUi selectTagForPairUi, RenamePairTagUi renamePairTagUi, LightlessMediator mediator, - TagHandler tagHandler, SelectPairForTagUi selectPairForTagUi, - ServerConfigurationManager serverConfigurationManager, UiSharedService uiSharedService, - PlayerPerformanceConfigService playerPerformanceConfigService, CharaDataManager charaDataManager, - SelectTagForSyncshellUi selectTagForSyncshellUi, RenameSyncshellTagUi renameSyncshellTagUi, SelectSyncshellForTagUi selectSyncshellForTagUi) + public DrawEntityFactory( + ILogger logger, + ApiController apiController, + IdDisplayHandler uidDisplayHandler, + SelectTagForPairUi selectTagForPairUi, + RenamePairTagUi renamePairTagUi, + LightlessMediator mediator, + TagHandler tagHandler, + SelectPairForTagUi selectPairForTagUi, + ServerConfigurationManager serverConfigurationManager, + LightlessConfigService configService, + UiSharedService uiSharedService, + PlayerPerformanceConfigService playerPerformanceConfigService, + CharaDataManager charaDataManager, + SelectTagForSyncshellUi selectTagForSyncshellUi, + RenameSyncshellTagUi renameSyncshellTagUi, + SelectSyncshellForTagUi selectSyncshellForTagUi, + PairLedger pairLedger, + PairFactory pairFactory) { _logger = logger; _apiController = apiController; @@ -46,44 +69,151 @@ public class DrawEntityFactory _tagHandler = tagHandler; _selectPairForTagUi = selectPairForTagUi; _serverConfigurationManager = serverConfigurationManager; + _configService = configService; _uiSharedService = uiSharedService; _playerPerformanceConfigService = playerPerformanceConfigService; _charaDataManager = charaDataManager; _selectTagForSyncshellUi = selectTagForSyncshellUi; _renameSyncshellTagUi = renameSyncshellTagUi; _selectSyncshellForTagUi = selectSyncshellForTagUi; + _pairLedger = pairLedger; + _pairFactory = pairFactory; } - public DrawFolderGroup CreateDrawGroupFolder(GroupFullInfoDto groupFullInfoDto, - Dictionary> filteredPairs, - IImmutableList allPairs) + public DrawFolderGroup CreateGroupFolder( + string id, + GroupFullInfoDto groupFullInfo, + IEnumerable drawEntries, + IEnumerable allEntries) { - return new DrawFolderGroup(groupFullInfoDto.Group.GID, groupFullInfoDto, _apiController, - filteredPairs.Select(p => CreateDrawPair(groupFullInfoDto.Group.GID + p.Key.UserData.UID, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), - allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectTagForSyncshellUi); + var drawPairs = drawEntries + .Select(entry => CreateDrawPair($"{id}:{entry.DisplayEntry.Ident.UserId}", entry, groupFullInfo)) + .Where(draw => draw is not null) + .Cast() + .ToImmutableList(); + + var allPairs = allEntries.ToImmutableList(); + + return new DrawFolderGroup( + id, + groupFullInfo, + _apiController, + drawPairs, + allPairs, + _tagHandler, + _uidDisplayHandler, + _mediator, + _uiSharedService, + _selectTagForSyncshellUi); } - public DrawFolderGroup CreateDrawGroupFolder(string id, GroupFullInfoDto groupFullInfoDto, - Dictionary> filteredPairs, - IImmutableList allPairs) + public DrawFolderTag CreateTagFolder( + string tag, + IEnumerable drawEntries, + IEnumerable allEntries) { - return new DrawFolderGroup(id, groupFullInfoDto, _apiController, - filteredPairs.Select(p => CreateDrawPair(groupFullInfoDto.Group.GID + p.Key.UserData.UID, p.Key, p.Value, groupFullInfoDto)).ToImmutableList(), - allPairs, _tagHandler, _uidDisplayHandler, _mediator, _uiSharedService, _selectTagForSyncshellUi); + var drawPairs = drawEntries + .Select(entry => CreateDrawPair($"{tag}:{entry.DisplayEntry.Ident.UserId}", entry)) + .Where(draw => draw is not null) + .Cast() + .ToImmutableList(); + + var allPairs = allEntries.ToImmutableList(); + + return new DrawFolderTag( + tag, + drawPairs, + allPairs, + _tagHandler, + _apiController, + _selectPairForTagUi, + _renamePairTagUi, + _uiSharedService, + _serverConfigurationManager, + _configService, + _mediator); } - public DrawFolderTag CreateDrawTagFolder(string tag, - Dictionary> filteredPairs, - IImmutableList allPairs) + public DrawUserPair? CreateDrawPair( + string id, + PairUiEntry entry, + GroupFullInfoDto? currentGroup = null) { - return new(tag, filteredPairs.Select(u => CreateDrawPair(tag, u.Key, u.Value, currentGroup: null)).ToImmutableList(), - allPairs, _tagHandler, _apiController, _selectPairForTagUi, _renamePairTagUi, _uiSharedService); + var pair = _pairFactory.Create(entry.DisplayEntry); + if (pair is null) + { + if (_logger.IsEnabled(LogLevel.Debug)) + { + _logger.LogDebug("Skipping draw pair for {UserId}: legacy pair not found.", entry.DisplayEntry.Ident.UserId); + } + return null; + } + + return new DrawUserPair( + id, + entry, + pair, + currentGroup, + _apiController, + _uidDisplayHandler, + _mediator, + _selectTagForPairUi, + _serverConfigurationManager, + _uiSharedService, + _playerPerformanceConfigService, + _charaDataManager, + _pairLedger); } - public DrawUserPair CreateDrawPair(string id, Pair user, List groups, GroupFullInfoDto? currentGroup) + public IReadOnlyList GetAllEntries() { - return new DrawUserPair(id + user.UserData.UID, user, groups, currentGroup, _apiController, _uidDisplayHandler, - _mediator, _selectTagForPairUi, _serverConfigurationManager, _uiSharedService, _playerPerformanceConfigService, - _charaDataManager); + try + { + return _pairLedger.GetAllEntries() + .Select(BuildUiEntry) + .ToList(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to build pair display entries."); + return Array.Empty(); + } + } + + private PairUiEntry BuildUiEntry(PairDisplayEntry entry) + { + var handler = entry.Handler; + var alias = entry.User.AliasOrUID; + if (string.IsNullOrWhiteSpace(alias)) + { + alias = entry.Ident.UserId; + } + + var displayName = !string.IsNullOrWhiteSpace(handler?.PlayerName) + ? handler!.PlayerName! + : alias; + + var note = _serverConfigurationManager.GetNoteForUid(entry.Ident.UserId) ?? string.Empty; + var isPaused = entry.SelfPermissions.IsPaused(); + + return new PairUiEntry( + entry, + alias, + displayName, + note, + entry.IsVisible, + entry.IsOnline, + entry.IsDirectlyPaired, + entry.IsOneSided, + entry.HasAnyConnection, + isPaused, + entry.SelfPermissions, + entry.OtherPermissions, + entry.PairStatus, + handler?.LastAppliedDataBytes ?? -1, + handler?.LastAppliedDataTris ?? -1, + handler?.LastAppliedApproximateVRAMBytes ?? -1, + handler?.LastAppliedApproximateEffectiveVRAMBytes ?? -1, + handler); } } \ No newline at end of file diff --git a/LightlessSync/UI/DtrEntry.cs b/LightlessSync/UI/DtrEntry.cs index 17bc871..f965181 100644 --- a/LightlessSync/UI/DtrEntry.cs +++ b/LightlessSync/UI/DtrEntry.cs @@ -5,7 +5,6 @@ using Dalamud.Plugin.Services; using Dalamud.Utility; using LightlessSync.LightlessConfiguration; using LightlessSync.LightlessConfiguration.Configurations; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; @@ -17,6 +16,8 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using System.Runtime.InteropServices; using System.Text; +using LightlessSync.UI.Services; +using LightlessSync.PlayerData.Pairs; using static LightlessSync.Services.PairRequestService; namespace LightlessSync.UI; @@ -37,7 +38,7 @@ public sealed class DtrEntry : IDisposable, IHostedService private readonly BroadcastService _broadcastService; private readonly BroadcastScannerService _broadcastScannerService; private readonly LightlessMediator _lightlessMediator; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly PairRequestService _pairRequestService; private readonly DalamudUtilService _dalamudUtilService; private Task? _runTask; @@ -57,7 +58,7 @@ public sealed class DtrEntry : IDisposable, IHostedService IDtrBar dtrBar, ConfigurationServiceBase configService, LightlessMediator lightlessMediator, - PairManager pairManager, + PairUiService pairUiService, PairRequestService pairRequestService, ApiController apiController, ServerConfigurationManager serverManager, @@ -71,7 +72,7 @@ public sealed class DtrEntry : IDisposable, IHostedService _lightfinderEntry = new(CreateLightfinderEntry); _configService = configService; _lightlessMediator = lightlessMediator; - _pairManager = pairManager; + _pairUiService = pairUiService; _pairRequestService = pairRequestService; _apiController = apiController; _serverManager = serverManager; @@ -165,7 +166,7 @@ public sealed class DtrEntry : IDisposable, IHostedService entry.OnClick = interactionEvent => OnLightfinderEntryClick(interactionEvent); return entry; } - + private void OnStatusEntryClick(DtrInteractionEvent interactionEvent) { if (interactionEvent.ClickType.Equals(MouseClickType.Left)) @@ -254,16 +255,15 @@ public sealed class DtrEntry : IDisposable, IHostedService if (_apiController.IsConnected) { - var pairCount = _pairManager.GetVisibleUserCount(); + var snapshot = _pairUiService.GetSnapshot(); + var visiblePairsQuery = snapshot.PairsByUid.Values.Where(x => x.IsVisible && !x.IsPaused); + var pairCount = visiblePairsQuery.Count(); text = $"\uE044 {pairCount}"; if (pairCount > 0) { var preferNote = config.PreferNoteInDtrTooltip; var showUid = config.ShowUidInDtrTooltip; - var visiblePairsQuery = _pairManager.GetOnlineUserPairs() - .Where(x => x.IsVisible); - IEnumerable visiblePairs = showUid ? visiblePairsQuery.Select(x => string.Format("{0} ({1})", preferNote ? x.GetNote() ?? x.PlayerName : x.PlayerName, x.UserData.AliasOrUID)) : visiblePairsQuery.Select(x => string.Format("{0}", preferNote ? x.GetNote() ?? x.PlayerName : x.PlayerName)); diff --git a/LightlessSync/UI/EditProfileUi.Group.cs b/LightlessSync/UI/EditProfileUi.Group.cs new file mode 100644 index 0000000..57f6c2f --- /dev/null +++ b/LightlessSync/UI/EditProfileUi.Group.cs @@ -0,0 +1,701 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; +using Dalamud.Interface.ImGuiFileDialog; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using LightlessSync.API.Data; +using LightlessSync.API.Dto.Group; +using LightlessSync.Services; +using LightlessSync.Services.Mediator; +using LightlessSync.UI.Tags; +using LightlessSync.Utils; +using Microsoft.Extensions.Logging; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +namespace LightlessSync.UI; + +public partial class EditProfileUi +{ + private void OpenGroupEditor(GroupFullInfoDto groupInfo) + { + _mode = ProfileEditorMode.Group; + _groupInfo = groupInfo; + + var profile = _lightlessProfileManager.GetLightlessGroupProfile(groupInfo.Group); + _groupProfileData = profile; + SyncGroupProfileState(profile, resetSelection: true); + + var scale = ImGuiHelpers.GlobalScale; + var viewport = ImGui.GetMainViewport(); + ProfileEditorLayoutCoordinator.Enable(groupInfo.Group.GID); + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); + Mediator.Publish(new GroupProfileOpenStandaloneMessage(groupInfo)); + + IsOpen = true; + _wasOpen = true; + } + + private void ResetGroupEditorState() + { + _groupInfo = null; + _groupProfileData = null; + _groupIsNsfw = false; + _groupIsDisabled = false; + _groupServerIsNsfw = false; + _groupServerIsDisabled = false; + _queuedProfileImage = null; + _queuedBannerImage = null; + _profileImage = Array.Empty(); + _bannerImage = Array.Empty(); + _profileDescription = string.Empty; + _descriptionText = string.Empty; + _profileTagIds = Array.Empty(); + _tagEditorSelection.Clear(); + _pfpTextureWrap?.Dispose(); + _pfpTextureWrap = null; + _bannerTextureWrap?.Dispose(); + _bannerTextureWrap = null; + _showProfileImageError = false; + _showBannerImageError = false; + } + + private void DrawGroupEditor(float scale) + { + if (_groupInfo is null) + { + UiSharedService.TextWrapped("Open the Syncshell admin panel and choose a group to edit its profile."); + return; + } + + var viewport = ImGui.GetMainViewport(); + var linked = ProfileEditorLayoutCoordinator.IsActive(_groupInfo.Group.GID); + + if (linked) + { + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); + + var desiredSize = ProfileEditorLayoutCoordinator.GetEditorSize(scale); + if (!ProfileEditorLayoutCoordinator.NearlyEquals(ImGui.GetWindowSize(), desiredSize)) + ImGui.SetWindowSize(desiredSize, ImGuiCond.Always); + + var currentPos = ImGui.GetWindowPos(); + if (IsWindowBeingDragged()) + ProfileEditorLayoutCoordinator.UpdateAnchorFromEditor(currentPos, scale); + + var desiredPos = ProfileEditorLayoutCoordinator.GetEditorPosition(scale); + if (!ProfileEditorLayoutCoordinator.NearlyEquals(currentPos, desiredPos)) + ImGui.SetWindowPos(desiredPos, ImGuiCond.Always); + } + else + { + var defaultProfilePos = viewport.WorkPos + new Vector2(50f, 70f) * scale; + var defaultEditorPos = defaultProfilePos + ProfileEditorLayoutCoordinator.GetEditorOffset(scale); + ImGui.SetWindowPos(defaultEditorPos, ImGuiCond.FirstUseEver); + } + + if (_queuedProfileImage is not null) + ApplyQueuedGroupProfileImage(); + if (_queuedBannerImage is not null) + ApplyQueuedGroupBannerImage(); + + var profile = _lightlessProfileManager.GetLightlessGroupProfile(_groupInfo.Group); + _groupProfileData = profile; + SyncGroupProfileState(profile, resetSelection: false); + + var accent = UIColors.Get("LightlessPurple"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.015f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.07f); + + using var panelBg = ImRaii.PushColor(ImGuiCol.ChildBg, accentBg); + using var panelBorder = ImRaii.PushColor(ImGuiCol.ChildBg, accentBorder); + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + + if (ImGui.BeginChild("##GroupProfileEditorCanvas", -Vector2.One, true, ImGuiWindowFlags.NoScrollbar)) + { + DrawGroupGuidelinesSection(scale); + ImGui.Dummy(new Vector2(0f, 4f * scale)); + DrawGroupProfileContent(profile, scale); + } + + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + private void DrawGroupGuidelinesSection(float scale) + { + DrawSection("Guidelines", scale, () => + { + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1f, 1f)); + + _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "All users that are paired and unpaused with you will be able to see your profile pictures, tags and description."); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Other users have the possibility to report this profile for breaking the rules."); + _uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.)"); + _uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Slurs of any kind in the description that can be considered highly offensive"); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "In case of valid reports from other users this can lead to disabling the profile forever or terminating syncshell owner's Lightless account indefinitely."); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Judgement of the profile validity from reports through staff is not up to debate and the decisions to disable the profile or your account permanent."); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessBlue"), "If the profile picture or profile description could be considered NSFW, enable the toggle in visibility settings."); + + ImGui.PopStyleVar(); + }); + } + + private void DrawGroupProfileContent(LightlessGroupProfileData profile, float scale) + { + DrawSection("Profile Preview", scale, () => DrawGroupProfileSnapshot(profile, scale)); + DrawSection("Profile Image", scale, DrawGroupProfileImageControls); + DrawSection("Profile Banner", scale, DrawGroupProfileBannerControls); + DrawSection("Profile Description", scale, DrawGroupProfileDescriptionEditor); + DrawSection("Profile Tags", scale, () => DrawGroupProfileTagsEditor(scale)); + DrawSection("Visibility", scale, DrawGroupProfileVisibilityControls); + } + + private void DrawGroupProfileSnapshot(LightlessGroupProfileData profile, float scale) + { + var bannerHeight = 140f * scale; + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##GroupProfileBannerPreview", new Vector2(-1f, bannerHeight), true)) + { + if (_bannerTextureWrap != null) + { + var childSize = ImGui.GetWindowSize(); + var padding = ImGui.GetStyle().WindowPadding; + var contentSize = new Vector2( + MathF.Max(childSize.X - padding.X * 2f, 1f), + MathF.Max(childSize.Y - padding.Y * 2f, 1f)); + + var imageSize = ImGuiHelpers.ScaledVector2(_bannerTextureWrap.Width, _bannerTextureWrap.Height); + if (imageSize.X > contentSize.X || imageSize.Y > contentSize.Y) + { + var ratio = MathF.Min(contentSize.X / MathF.Max(imageSize.X, 1f), contentSize.Y / MathF.Max(imageSize.Y, 1f)); + imageSize *= ratio; + } + + var offset = new Vector2( + MathF.Max((contentSize.X - imageSize.X) * 0.5f, 0f), + MathF.Max((contentSize.Y - imageSize.Y) * 0.5f, 0f)); + ImGui.SetCursorPos(padding + offset); + ImGui.Image(_bannerTextureWrap.Handle, imageSize); + } + else + { + ImGui.TextColored(UIColors.Get("LightlessPurple"), "No profile banner uploaded."); + } + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + + ImGui.Dummy(new Vector2(0f, 6f * scale)); + + if (_pfpTextureWrap != null) + { + var size = ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height); + var maxEdge = 160f * scale; + if (size.X > maxEdge || size.Y > maxEdge) + { + var ratio = MathF.Min(maxEdge / MathF.Max(size.X, 1f), maxEdge / MathF.Max(size.Y, 1f)); + size *= ratio; + } + + ImGui.Image(_pfpTextureWrap.Handle, size); + } + else + { + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##GroupProfileImagePlaceholder", new Vector2(160f * scale, 160f * scale), true)) + ImGui.TextColored(UIColors.Get("LightlessPurple"), "No profile picture uploaded."); + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + ImGui.SameLine(); + ImGui.BeginGroup(); + ImGui.TextColored(UIColors.Get("LightlessBlue"), _groupInfo!.GroupAliasOrGID); + ImGui.TextDisabled($"ID: {_groupInfo.Group.GID}"); + ImGui.TextDisabled($"Owner: {_groupInfo.Owner.AliasOrUID}"); + ImGui.EndGroup(); + + ImGui.Dummy(new Vector2(0f, 4f * scale)); + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##GroupProfileDescriptionPreview", new Vector2(-1f, 120f * scale), true)) + { + var hasDescription = !string.IsNullOrWhiteSpace(profile.Description); + ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); + if (!hasDescription) + { + ImGui.TextDisabled("Syncshell has no description set."); + } + else if (!SeStringUtils.TryRenderSeStringMarkupAtCursor(profile.Description!)) + { + UiSharedService.TextWrapped(profile.Description); + } + ImGui.PopTextWrapPos(); + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + + ImGui.Dummy(new Vector2(0f, 4f * scale)); + ImGui.TextColored(UIColors.Get("LightlessBlue"), "Saved Tags"); + var savedTags = _profileTagService.ResolveTags(_profileTagIds); + if (savedTags.Count == 0) + { + ImGui.TextDisabled("-- No tags set --"); + } + else + { + bool first = true; + for (int i = 0; i < savedTags.Count; i++) + { + if (!savedTags[i].HasContent) + continue; + + if (!first) + ImGui.SameLine(0f, 6f * scale); + first = false; + + using (ImRaii.PushId($"group-snapshot-tag-{i}")) + DrawTagPreview(savedTags[i], scale, "##groupSnapshotTagPreview"); + } + if (!first) + ImGui.NewLine(); + } + } + + private void DrawGroupProfileImageControls() + { + _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "Profile pictures must be 512x512 and under 2 MiB."); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture")) + { + _fileDialogManager.OpenFileDialog("Select syncshell profile picture", ImageFileDialogFilter, (success, file) => + { + if (!success || string.IsNullOrEmpty(file)) + return; + _showProfileImageError = false; + _ = SubmitGroupProfilePicture(file); + }); + } + UiSharedService.AttachToolTip("Select an image up to 512x512 pixels and <= 2 MiB (PNG/JPG/JPEG/WEBP/BMP)."); + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear profile picture")) + { + _ = ClearGroupProfilePicture(); + } + UiSharedService.AttachToolTip("Remove the current profile picture from this syncshell."); + + if (_showProfileImageError) + { + UiSharedService.ColorTextWrapped("Image must be no larger than 512x512 pixels and under 2 MiB.", ImGuiColors.DalamudRed); + } + } + + private void DrawGroupProfileBannerControls() + { + _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "Profile banners must be 840x260 and under 2 MiB."); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile banner")) + { + _fileDialogManager.OpenFileDialog("Select syncshell profile banner", ImageFileDialogFilter, (success, file) => + { + if (!success || string.IsNullOrEmpty(file)) + return; + _showBannerImageError = false; + _ = SubmitGroupProfileBanner(file); + }); + } + UiSharedService.AttachToolTip("Select an image up to 840x260 pixels and <= 2 MiB (PNG/JPG/JPEG/WEBP/BMP)."); + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear profile banner")) + { + _ = ClearGroupProfileBanner(); + } + UiSharedService.AttachToolTip("Remove the current profile banner."); + + if (_showBannerImageError) + { + UiSharedService.ColorTextWrapped("Banner must be no larger than 840x260 pixels and under 2 MiB.", ImGuiColors.DalamudRed); + } + } + + private void DrawGroupProfileDescriptionEditor() + { + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(6f, 4f) * ImGuiHelpers.GlobalScale); + var descriptionBoxSize = new Vector2(-1f, 160f * ImGuiHelpers.GlobalScale); + ImGui.InputTextMultiline("##GroupDescription", ref _descriptionText, 1500, descriptionBoxSize); + ImGui.PopStyleVar(); + + ImGui.TextDisabled($"{_descriptionText.Length}/1500 characters"); + ImGui.SameLine(); + ImGuiComponents.HelpMarker(DescriptionMacroTooltip); + + bool changed = !string.Equals(_descriptionText, _profileDescription, StringComparison.Ordinal); + if (!changed) + ImGui.BeginDisabled(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description")) + { + _ = SubmitGroupDescription(_descriptionText); + } + UiSharedService.AttachToolTip("Apply the text above to the syncshell profile description."); + if (!changed) + ImGui.EndDisabled(); + + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description")) + { + _ = SubmitGroupDescription(string.Empty); + } + UiSharedService.AttachToolTip("Remove the profile description."); + } + + private void DrawGroupProfileTagsEditor(float scale) + { + DrawTagEditor( + scale, + contextPrefix: "group", + saveTooltip: "Apply the selected tags to this syncshell profile.", + submitAction: payload => SubmitGroupTagChanges(payload), + allowReorder: true, + sortPayloadBeforeSubmit: true, + onPayloadPrepared: payload => + { + _tagEditorSelection.Clear(); + if (payload.Length > 0) + _tagEditorSelection.AddRange(payload); + }); + } + + private void DrawGroupProfileVisibilityControls() + { + bool changedNsfw = DrawCheckboxRow("Profile is NSFW", _groupIsNsfw, out var newNsfw, "Flag this profile as not safe for work."); + if (changedNsfw) + _groupIsNsfw = newNsfw; + + bool changedDisabled = DrawCheckboxRow("Disable profile for viewers", _groupIsDisabled, out var newDisabled, "Temporarily hide this profile from members."); + if (changedDisabled) + _groupIsDisabled = newDisabled; + + bool visibilityChanged = (_groupIsNsfw != _groupServerIsNsfw) || (_groupIsDisabled != _groupServerIsDisabled); + + if (!visibilityChanged) + ImGui.BeginDisabled(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Apply Visibility Changes")) + { + _ = SubmitGroupVisibilityChanges(_groupIsNsfw, _groupIsDisabled); + } + UiSharedService.AttachToolTip("Apply the visibility toggles above."); + if (!visibilityChanged) + ImGui.EndDisabled(); + + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.SyncAlt, "Reset")) + { + _groupIsNsfw = _groupServerIsNsfw; + _groupIsDisabled = _groupServerIsDisabled; + } + } + + private string? GetCurrentGroupProfileImageBase64() + { + if (_queuedProfileImage is not null && _queuedProfileImage.Length > 0) + return Convert.ToBase64String(_queuedProfileImage); + + if (!string.IsNullOrWhiteSpace(_groupProfileData?.Base64ProfilePicture)) + return _groupProfileData!.Base64ProfilePicture; + + return _profileImage.Length > 0 ? Convert.ToBase64String(_profileImage) : null; + } + + private string? GetCurrentGroupBannerBase64() + { + if (_queuedBannerImage is not null && _queuedBannerImage.Length > 0) + return Convert.ToBase64String(_queuedBannerImage); + + if (!string.IsNullOrWhiteSpace(_groupProfileData?.Base64BannerPicture)) + return _groupProfileData!.Base64BannerPicture; + + return _bannerImage.Length > 0 ? Convert.ToBase64String(_bannerImage) : null; + } + + private async Task SubmitGroupProfilePicture(string filePath) + { + if (_groupInfo is null) + return; + + try + { + var fileContent = await File.ReadAllBytesAsync(filePath).ConfigureAwait(false); + await using var stream = new MemoryStream(fileContent); + var format = await Image.DetectFormatAsync(stream).ConfigureAwait(false); + if (!IsSupportedImageFormat(format)) + { + _showProfileImageError = true; + return; + } + + using var image = Image.Load(fileContent); + if (image.Width > 512 || image.Height > 512 || fileContent.Length > 2000 * 1024) + { + _showProfileImageError = true; + return; + } + + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: null, + Tags: null, + PictureBase64: Convert.ToBase64String(fileContent), + BannerBase64: null, + IsNsfw: null, + IsDisabled: null)).ConfigureAwait(false); + + _showProfileImageError = false; + _queuedProfileImage = fileContent; + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to upload syncshell profile picture."); + } + } + + private async Task ClearGroupProfilePicture() + { + if (_groupInfo is null) + return; + + try + { + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: null, + Tags: null, + PictureBase64: null, + BannerBase64: null, + IsNsfw: null, + IsDisabled: null)).ConfigureAwait(false); + + _queuedProfileImage = Array.Empty(); + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to clear syncshell profile picture."); + } + } + + private async Task SubmitGroupProfileBanner(string filePath) + { + if (_groupInfo is null) + return; + + try + { + var fileContent = await File.ReadAllBytesAsync(filePath).ConfigureAwait(false); + await using var stream = new MemoryStream(fileContent); + var format = await Image.DetectFormatAsync(stream).ConfigureAwait(false); + if (!IsSupportedImageFormat(format)) + { + _showBannerImageError = true; + return; + } + + using var image = Image.Load(fileContent); + if (image.Width > 840 || image.Height > 260 || fileContent.Length > 2000 * 1024) + { + _showBannerImageError = true; + return; + } + + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: null, + Tags: null, + PictureBase64: null, + BannerBase64: Convert.ToBase64String(fileContent), + IsNsfw: null, + IsDisabled: null)).ConfigureAwait(false); + + _showBannerImageError = false; + _queuedBannerImage = fileContent; + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to upload syncshell profile banner."); + } + } + + private async Task ClearGroupProfileBanner() + { + if (_groupInfo is null) + return; + + try + { + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: null, + Tags: null, + PictureBase64: null, + BannerBase64: null, + IsNsfw: null, + IsDisabled: null)).ConfigureAwait(false); + + _queuedBannerImage = Array.Empty(); + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to clear syncshell profile banner."); + } + } + + private async Task SubmitGroupDescription(string description) + { + if (_groupInfo is null) + return; + + try + { + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: description, + Tags: null, + PictureBase64: GetCurrentGroupProfileImageBase64(), + BannerBase64: GetCurrentGroupBannerBase64(), + IsNsfw: null, + IsDisabled: null)).ConfigureAwait(false); + + _profileDescription = description; + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to update syncshell profile description."); + } + } + + private async Task SubmitGroupTagChanges(int[] payload) + { + if (_groupInfo is null) + return; + + try + { + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: null, + Tags: payload, + PictureBase64: GetCurrentGroupProfileImageBase64(), + BannerBase64: GetCurrentGroupBannerBase64(), + IsNsfw: null, + IsDisabled: null)).ConfigureAwait(false); + + _profileTagIds = payload.Length == 0 ? Array.Empty() : payload.ToArray(); + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to update syncshell profile tags."); + } + } + + private async Task SubmitGroupVisibilityChanges(bool isNsfw, bool isDisabled) + { + if (_groupInfo is null) + return; + + try + { + await _apiController.GroupSetProfile(new GroupProfileDto( + _groupInfo.Group, + Description: null, + Tags: null, + PictureBase64: GetCurrentGroupProfileImageBase64(), + BannerBase64: GetCurrentGroupBannerBase64(), + IsNsfw: isNsfw, + IsDisabled: isDisabled)).ConfigureAwait(false); + + _groupServerIsNsfw = isNsfw; + _groupServerIsDisabled = isDisabled; + Mediator.Publish(new ClearProfileGroupDataMessage(_groupInfo.Group)); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to update syncshell profile visibility."); + } + } + + private void ApplyQueuedGroupProfileImage() + { + if (_queuedProfileImage is null) + return; + + _profileImage = _queuedProfileImage; + _pfpTextureWrap?.Dispose(); + _pfpTextureWrap = _profileImage.Length > 0 ? _uiSharedService.LoadImage(_profileImage) : null; + _queuedProfileImage = null; + } + + private void ApplyQueuedGroupBannerImage() + { + if (_queuedBannerImage is null) + return; + + _bannerImage = _queuedBannerImage; + _bannerTextureWrap?.Dispose(); + _bannerTextureWrap = _bannerImage.Length > 0 ? _uiSharedService.LoadImage(_bannerImage) : null; + _queuedBannerImage = null; + } + + private void SyncGroupProfileState(LightlessGroupProfileData profile, bool resetSelection) + { + if (!_profileImage.SequenceEqual(profile.ProfileImageData.Value)) + { + _profileImage = profile.ProfileImageData.Value; + _pfpTextureWrap?.Dispose(); + _pfpTextureWrap = _profileImage.Length > 0 ? _uiSharedService.LoadImage(_profileImage) : null; + } + + if (!_bannerImage.SequenceEqual(profile.BannerImageData.Value)) + { + _bannerImage = profile.BannerImageData.Value; + _bannerTextureWrap?.Dispose(); + _bannerTextureWrap = _bannerImage.Length > 0 ? _uiSharedService.LoadImage(_bannerImage) : null; + } + + if (!string.Equals(_profileDescription, profile.Description, StringComparison.Ordinal)) + { + _profileDescription = profile.Description; + _descriptionText = _profileDescription; + } + + var tags = profile.Tags ?? Array.Empty(); + if (!TagsEqual(tags, _profileTagIds)) + { + _profileTagIds = tags.Count == 0 ? Array.Empty() : tags.ToArray(); + if (resetSelection) + { + _tagEditorSelection.Clear(); + if (_profileTagIds.Length > 0) + _tagEditorSelection.AddRange(_profileTagIds); + } + } + + _groupIsNsfw = profile.IsNsfw; + _groupIsDisabled = profile.IsDisabled; + _groupServerIsNsfw = profile.IsNsfw; + _groupServerIsDisabled = profile.IsDisabled; + } + +} + diff --git a/LightlessSync/UI/EditProfileUi.cs b/LightlessSync/UI/EditProfileUi.cs index 5dedf81..62d4bde 100644 --- a/LightlessSync/UI/EditProfileUi.cs +++ b/LightlessSync/UI/EditProfileUi.cs @@ -1,37 +1,93 @@ -using Dalamud.Bindings.ImGui; +using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using LightlessSync.API.Data; +using LightlessSync.API.Dto.Group; using LightlessSync.API.Dto.User; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.UI.Style; +using LightlessSync.UI.Tags; using LightlessSync.Utils; using LightlessSync.WebAPI; using Microsoft.Extensions.Logging; using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Collections.Generic; +using System.IO; using System.Numerics; +using System.Threading.Tasks; +using System.Linq; namespace LightlessSync.UI; -public class EditProfileUi : WindowMediatorSubscriberBase +public partial class EditProfileUi : WindowMediatorSubscriberBase { private readonly ApiController _apiController; private readonly FileDialogManager _fileDialogManager; private readonly LightlessProfileManager _lightlessProfileManager; private readonly UiSharedService _uiSharedService; - private bool _adjustedForScollBarsLocalProfile = false; - private bool _adjustedForScollBarsOnlineProfile = false; + private readonly ProfileTagService _profileTagService; + private const string LoadingProfileDescription = "Loading Profile Data from server..."; + private const string DescriptionMacroTooltip = + "Supported SeString markup:\n" + + "
- insert a line break (Enter already emits these).\n" + + "<-> - optional soft hyphen / word break.\n" + + " / - show game icons by numeric id;" + + "text or - tint text; reset with or .\n" + + " / - use UI palette colours (0 restores defaults).\n" + + " / - change outline colour.\n" + + " - toggle style flags.\n" + + " - create clickable links."; + + private static readonly HashSet SupportedImageExtensions = new(StringComparer.OrdinalIgnoreCase) + { + "png", + "jpg", + "jpeg", + "webp", + "bmp" + }; + private const string ImageFileDialogFilter = "Images{.png,.jpg,.jpeg,.webp,.bmp}"; + private readonly List _tagEditorSelection = new(); + private int[] _profileTagIds = Array.Empty(); + private readonly List _tagPreviewSegments = new(); + private enum ProfileEditorMode + { + User, + Group + } + + private ProfileEditorMode _mode = ProfileEditorMode.User; + private GroupFullInfoDto? _groupInfo; + private LightlessGroupProfileData? _groupProfileData; + private bool _groupIsNsfw; + private bool _groupIsDisabled; + private bool _groupServerIsNsfw; + private bool _groupServerIsDisabled; + private byte[]? _queuedProfileImage; + private byte[]? _queuedBannerImage; + private readonly Vector4 _tagBackgroundColor = new(0.18f, 0.18f, 0.18f, 0.95f); + private readonly Vector4 _tagBorderColor = new(0.35f, 0.35f, 0.35f, 0.4f); + private const int MaxProfileTags = 12; + private const int AvailableTagsPerPage = 6; + private int _availableTagPage; + private UserData? _selfProfileUserData; private string _descriptionText = string.Empty; private IDalamudTextureWrap? _pfpTextureWrap; + private IDalamudTextureWrap? _bannerTextureWrap; private string _profileDescription = string.Empty; private byte[] _profileImage = []; - private bool _showFileDialogError = false; + private byte[] _bannerImage = []; + private bool _showProfileImageError = false; + private bool _showBannerImageError = false; private bool _wasOpen; private Vector4 _currentBg = new(0.15f, 0.15f, 0.15f, 1f); @@ -46,23 +102,33 @@ public class EditProfileUi : WindowMediatorSubscriberBase public EditProfileUi(ILogger logger, LightlessMediator mediator, ApiController apiController, UiSharedService uiSharedService, FileDialogManager fileDialogManager, - LightlessProfileManager lightlessProfileManager, PerformanceCollectorService performanceCollectorService) + LightlessProfileManager lightlessProfileManager, ProfileTagService profileTagService, PerformanceCollectorService performanceCollectorService) : base(logger, mediator, "Lightless Sync Edit Profile###LightlessSyncEditProfileUI", performanceCollectorService) { IsOpen = false; - this.SizeConstraints = new() + var scale = ImGuiHelpers.GlobalScale; + var editorSize = ProfileEditorLayoutCoordinator.GetEditorSize(scale); + Size = editorSize; + SizeCondition = ImGuiCond.FirstUseEver; + SizeConstraints = new() { - MinimumSize = new(850, 640), - MaximumSize = new(850, 700) + MinimumSize = editorSize, + MaximumSize = editorSize }; + Flags |= ImGuiWindowFlags.NoResize; _apiController = apiController; _uiSharedService = uiSharedService; _fileDialogManager = fileDialogManager; _lightlessProfileManager = lightlessProfileManager; + _profileTagService = profileTagService; Mediator.Subscribe(this, (_) => { _wasOpen = IsOpen; IsOpen = false; }); Mediator.Subscribe(this, (_) => IsOpen = _wasOpen); - Mediator.Subscribe(this, (_) => IsOpen = false); + Mediator.Subscribe(this, (_) => + { + IsOpen = false; + _selfProfileUserData = null; + }); Mediator.Subscribe(this, (msg) => { if (msg.UserData == null || string.Equals(msg.UserData.UID, _apiController.UID, StringComparison.Ordinal)) @@ -73,8 +139,17 @@ public class EditProfileUi : WindowMediatorSubscriberBase }); Mediator.Subscribe(this, msg => { + _selfProfileUserData = msg.Connection.User with + { + IsAdmin = msg.Connection.IsAdmin, + IsModerator = msg.Connection.IsModerator, + HasVanity = msg.Connection.HasVanity, + TextColorHex = msg.Connection.TextColorHex, + TextGlowColorHex = msg.Connection.TextGlowColorHex + }; LoadVanity(); }); + Mediator.Subscribe(this, msg => OpenGroupEditor(msg.Group)); } private void LoadVanity() @@ -89,309 +164,1111 @@ public class EditProfileUi : WindowMediatorSubscriberBase vanityInitialized = true; } + public override async void OnOpen() + { + if (_mode == ProfileEditorMode.Group) + { + if (_groupInfo is not null) + { + var scale = ImGuiHelpers.GlobalScale; + var viewport = ImGui.GetMainViewport(); + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); + } + return; + } + + var user = await EnsureSelfProfileUserDataAsync().ConfigureAwait(false); + if (user is not null) + { + ProfileEditorLayoutCoordinator.Enable(user.UID); + var scale = ImGuiHelpers.GlobalScale; + var viewport = ImGui.GetMainViewport(); + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); + Mediator.Publish(new OpenSelfProfilePreviewMessage(user)); + } + } + + public override void OnClose() + { + if (_mode == ProfileEditorMode.Group) + { + if (_groupInfo is not null) + { + ProfileEditorLayoutCoordinator.Disable(_groupInfo.Group.GID); + Mediator.Publish(new CloseGroupProfilePreviewMessage(_groupInfo)); + } + + ResetGroupEditorState(); + _mode = ProfileEditorMode.User; + return; + } + + if (_selfProfileUserData is not null) + { + ProfileEditorLayoutCoordinator.Disable(_selfProfileUserData.UID); + Mediator.Publish(new CloseSelfProfilePreviewMessage(_selfProfileUserData)); + } + } + + private async Task EnsureSelfProfileUserDataAsync() + { + if (_selfProfileUserData is not null) + return _selfProfileUserData; + + try + { + var connection = await _apiController.GetConnectionDtoAsync(publishConnected: false).ConfigureAwait(false); + _selfProfileUserData = connection.User with + { + IsAdmin = connection.IsAdmin, + IsModerator = connection.IsModerator, + HasVanity = connection.HasVanity, + TextColorHex = connection.TextColorHex, + TextGlowColorHex = connection.TextGlowColorHex + }; + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to acquire connection information for profile preview."); + } + + return _selfProfileUserData; + } + protected override void DrawInternal() { + var scale = ImGuiHelpers.GlobalScale; - _uiSharedService.UnderlinedBigText("Notes and Rules for Profiles", UIColors.Get("LightlessYellow")); - ImGui.Dummy(new Vector2(5)); + if (_mode == ProfileEditorMode.Group) + { + DrawGroupEditor(scale); + return; + } - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 1)); + var viewport = ImGui.GetMainViewport(); + var linked = _selfProfileUserData is not null && ProfileEditorLayoutCoordinator.IsActive(_selfProfileUserData.UID); - _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "All users that are paired and unpaused with you will be able to see your profile picture and description."); - _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Other users have the possibility to report your profile for breaking the rules."); - _uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.)"); - _uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Slurs of any kind in the description that can be considered highly offensive"); - _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "In case of valid reports from other users this can lead to disabling your profile forever or terminating your Lightless account indefinitely."); - _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Judgement of your profile validity from reports through staff is not up to debate and the decisions to disable your profile/account permanent."); - _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessBlue"), "If your profile picture or profile description could be considered NSFW, enable the toggle in profile settings."); + if (linked) + { + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); - ImGui.PopStyleVar(); + var desiredSize = ProfileEditorLayoutCoordinator.GetEditorSize(scale); + if (!ProfileEditorLayoutCoordinator.NearlyEquals(ImGui.GetWindowSize(), desiredSize)) + ImGui.SetWindowSize(desiredSize, ImGuiCond.Always); - ImGui.Dummy(new Vector2(3)); + var currentPos = ImGui.GetWindowPos(); + if (IsWindowBeingDragged()) + ProfileEditorLayoutCoordinator.UpdateAnchorFromEditor(currentPos, scale); + + var desiredPos = ProfileEditorLayoutCoordinator.GetEditorPosition(scale); + if (!ProfileEditorLayoutCoordinator.NearlyEquals(currentPos, desiredPos)) + ImGui.SetWindowPos(desiredPos, ImGuiCond.Always); + } + else + { + var defaultProfilePos = viewport.WorkPos + new Vector2(50f, 70f) * scale; + var defaultEditorPos = defaultProfilePos + ProfileEditorLayoutCoordinator.GetEditorOffset(scale); + ImGui.SetWindowPos(defaultEditorPos, ImGuiCond.FirstUseEver); + } var profile = _lightlessProfileManager.GetLightlessUserProfile(new UserData(_apiController.UID)); - _logger.LogInformation("Profile fetched for drawing: {profile}", profile); - if (ImGui.BeginTabBar("##EditProfileTabs")) - { - if (ImGui.BeginTabItem("Current Profile")) + var accent = UIColors.Get("LightlessPurple"); + var accentBg = new Vector4(accent.X, accent.Y, accent.Z, 0.015f); + var accentBorder = new Vector4(accent.X, accent.Y, accent.Z, 0.07f); + + using var panelBg = ImRaii.PushColor(ImGuiCol.ChildBg, accentBg); + using var panelBorder = ImRaii.PushColor(ImGuiCol.ChildBg, accentBorder); + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + + if (ImGui.BeginChild("##ProfileEditorCanvas", -Vector2.One, true, ImGuiWindowFlags.NoScrollbar)) + { + DrawGuidelinesSection(scale); + ImGui.Dummy(new Vector2(0f, 4f * scale)); + DrawTabInterface(profile, scale); + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + private void DrawGuidelinesSection(float scale) + { + DrawSection("Guidelines", scale, () => + { + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(1, 1)); + + _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "All users that are paired and unpaused with you will be able to see your profile pictures, tags and description."); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Other users have the possibility to report your profile for breaking the rules."); + _uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Anything as profile image that can be considered highly illegal or obscene (bestiality, anything that could be considered a sexual act with a minor (that includes Lalafells), etc.)"); + _uiSharedService.DrawNoteLine("!!! ", UIColors.Get("DimRed"), "AVOID: Slurs of any kind in the description that can be considered highly offensive"); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "In case of valid reports from other users this can lead to disabling your profile forever or terminating your Lightless account indefinitely."); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), "Judgement of your profile validity from reports through staff is not up to debate and the decisions to disable your profile/account permanent."); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessBlue"), "If your profile picture or profile description could be considered NSFW, enable the toggle in visibility settings."); + + ImGui.PopStyleVar(); + }); + } + + private void DrawTabInterface(LightlessUserProfileData profile, float scale) + { + ImGui.PushStyleVar(ImGuiStyleVar.TabRounding, 4f * scale); + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8f, 4f) * scale); + + if (ImGui.BeginTabBar("##ProfileEditorTabs", ImGuiTabBarFlags.NoCloseWithMiddleMouseButton | ImGuiTabBarFlags.FittingPolicyResizeDown)) + { + if (ImGui.BeginTabItem("Profile")) { - _uiSharedService.MediumText("Current Profile (as saved on server)", UIColors.Get("LightlessPurple")); - ImGui.Dummy(new Vector2(5)); - - if (profile.IsFlagged) - { - UiSharedService.ColorTextWrapped(profile.Description, ImGuiColors.DalamudRed); - return; - } - - if (!_profileImage.SequenceEqual(profile.ImageData.Value)) - { - _profileImage = profile.ImageData.Value; - _pfpTextureWrap?.Dispose(); - _pfpTextureWrap = _uiSharedService.LoadImage(_profileImage); - } - - if (!string.Equals(_profileDescription, profile.Description, StringComparison.OrdinalIgnoreCase)) - { - _profileDescription = profile.Description; - _descriptionText = _profileDescription; - } - - if (_pfpTextureWrap != null) - { - ImGui.Image(_pfpTextureWrap.Handle, ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height)); - } - - var spacing = ImGui.GetStyle().ItemSpacing.X; - ImGuiHelpers.ScaledRelativeSameLine(256, spacing); - using (_uiSharedService.GameFont.Push()) - { - var descriptionTextSize = ImGui.CalcTextSize(profile.Description, wrapWidth: 256f); - var childFrame = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 256); - if (descriptionTextSize.Y > childFrame.Y) - { - _adjustedForScollBarsOnlineProfile = true; - } - else - { - _adjustedForScollBarsOnlineProfile = false; - } - childFrame = childFrame with - { - X = childFrame.X + (_adjustedForScollBarsOnlineProfile ? ImGui.GetStyle().ScrollbarSize : 0), - }; - if (ImGui.BeginChildFrame(101, childFrame)) - { - UiSharedService.TextWrapped(profile.Description); - } - ImGui.EndChildFrame(); - } - - var nsfw = profile.IsNSFW; - ImGui.BeginDisabled(); - ImGui.Checkbox("Is NSFW", ref nsfw); - ImGui.EndDisabled(); - - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + DrawProfileTabContent(profile, scale); ImGui.EndTabItem(); } - if (ImGui.BeginTabItem("Profile Settings")) + if (ImGui.BeginTabItem("Vanity")) { - _uiSharedService.MediumText("Profile Settings", UIColors.Get("LightlessPurple")); - ImGui.Dummy(new Vector2(5)); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture")) - { - _fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) => - { - if (!success) return; - _ = Task.Run(async () => - { - var fileContent = File.ReadAllBytes(file); - using MemoryStream ms = new(fileContent); - var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false); - if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase)) - { - _showFileDialogError = true; - return; - } - using var image = Image.Load(fileContent); - - if (image.Width > 256 || image.Height > 256 || (fileContent.Length > 250 * 1024)) - { - _showFileDialogError = true; - return; - } - - _showFileDialogError = false; - await _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, Convert.ToBase64String(fileContent), BannerPictureBase64: null, Description: null, Tags: null)) - .ConfigureAwait(false); - }); - }); - } - UiSharedService.AttachToolTip("Select and upload a new profile picture"); - ImGui.SameLine(); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear uploaded profile picture")) - { - _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, "", Description: null, BannerPictureBase64: null, Tags: null)); - } - UiSharedService.AttachToolTip("Clear your currently uploaded profile picture"); - if (_showFileDialogError) - { - UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", ImGuiColors.DalamudRed); - } - var isNsfw = profile.IsNSFW; - if (ImGui.Checkbox("Profile is NSFW", ref isNsfw)) - { - _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, isNsfw, ProfilePictureBase64: null, Description: null, BannerPictureBase64: null, Tags: null)); - } - _uiSharedService.DrawHelpText("If your profile description or image can be considered NSFW, toggle this to ON"); - var widthTextBox = 400; - var posX = ImGui.GetCursorPosX(); - ImGui.TextUnformatted($"Description {_descriptionText.Length}/1500"); - ImGui.SetCursorPosX(posX); - ImGuiHelpers.ScaledRelativeSameLine(widthTextBox, ImGui.GetStyle().ItemSpacing.X); - ImGui.TextUnformatted("Preview (approximate)"); - using (_uiSharedService.GameFont.Push()) - ImGui.InputTextMultiline("##description", ref _descriptionText, 1500, ImGuiHelpers.ScaledVector2(widthTextBox, 200)); - - ImGui.SameLine(); - - using (_uiSharedService.GameFont.Push()) - { - var descriptionTextSizeLocal = ImGui.CalcTextSize(_descriptionText, wrapWidth: 256f); - var childFrameLocal = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 200); - if (descriptionTextSizeLocal.Y > childFrameLocal.Y) - { - _adjustedForScollBarsLocalProfile = true; - } - else - { - _adjustedForScollBarsLocalProfile = false; - } - childFrameLocal = childFrameLocal with - { - X = childFrameLocal.X + (_adjustedForScollBarsLocalProfile ? ImGui.GetStyle().ScrollbarSize : 0), - }; - if (ImGui.BeginChildFrame(102, childFrameLocal)) - { - UiSharedService.TextWrapped(_descriptionText); - } - ImGui.EndChildFrame(); - } - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description")) - { - _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, BannerPictureBase64: null, _descriptionText, Tags: null)); - } - UiSharedService.AttachToolTip("Sets your profile description text"); - ImGui.SameLine(); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description")) - { - _ = _apiController.UserSetProfile(new UserProfileDto(new UserData(_apiController.UID), Disabled: false, IsNSFW: null, ProfilePictureBase64: null, BannerPictureBase64: null, "", Tags: null)); - } - UiSharedService.AttachToolTip("Clears your profile description text"); - - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem("Vanity Settings")) - { - _uiSharedService.MediumText("Supporter Vanity Settings", UIColors.Get("LightlessPurple")); - ImGui.Dummy(new Vector2(4)); - _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessPurple"), "Must be a supporter through Patreon/Ko-fi to access these settings. If you have the vanity role, you must interact with the Discord bot first."); - - var hasVanity = _apiController.HasVanity; - - if (!hasVanity) - { - UiSharedService.ColorTextWrapped("You do not currently have vanity access. Become a supporter to unlock these features.", UIColors.Get("DimRed")); - ImGui.Dummy(new Vector2(8)); - ImGui.BeginDisabled(); - } - - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f); - _uiSharedService.MediumText("Colored UID", UIColors.Get("LightlessPurple")); - ImGui.Dummy(new Vector2(5)); - - var font = UiBuilder.MonoFont; - var playerUID = _apiController.UID; - var playerDisplay = _apiController.DisplayName; - - var previewTextColor = textEnabled ? textColor : Vector4.One; - var previewGlowColor = glowEnabled ? glowColor : Vector4.Zero; - - var seString = SeStringUtils.BuildFormattedPlayerName(playerDisplay, previewTextColor, previewGlowColor); - - using (ImRaii.PushFont(font)) - { - var drawList = ImGui.GetWindowDrawList(); - var textSize = ImGui.CalcTextSize(seString.TextValue); - - float minWidth = 150f * ImGuiHelpers.GlobalScale; - float bgWidth = Math.Max(textSize.X + 20f, minWidth); - - float paddingY = 5f * ImGuiHelpers.GlobalScale; - - var cursor = ImGui.GetCursorScreenPos(); - - var rectMin = cursor; - var rectMax = rectMin + new Vector2(bgWidth, textSize.Y + (paddingY * 2f)); - - float boost = Luminance.ComputeHighlight(previewTextColor, previewGlowColor); - - var baseBg = new Vector4(0.15f + boost, 0.15f + boost, 0.15f + boost, 1f); - var bgColor = Luminance.BackgroundContrast(previewTextColor, previewGlowColor, baseBg, ref _currentBg); - - var borderColor = UIColors.Get("LightlessPurple"); - - drawList.AddRectFilled(rectMin, rectMax, ImGui.GetColorU32(bgColor), 6.0f); - drawList.AddRect(rectMin, rectMax, ImGui.GetColorU32(borderColor), 6.0f, ImDrawFlags.None, 1.5f); - - var textPos = new Vector2( - rectMin.X + (bgWidth - textSize.X) * 0.5f, - rectMin.Y + paddingY - ); - - SeStringUtils.RenderSeStringWithHitbox(seString, textPos, font); - - ImGui.Dummy(new Vector2(5)); - } - - const float colorPickAlign = 90f; - - _uiSharedService.DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Text Color"); - ImGui.SameLine(colorPickAlign); - ImGui.Checkbox("##toggleTextColor", ref textEnabled); - ImGui.SameLine(); - ImGui.BeginDisabled(!textEnabled); - ImGui.ColorEdit4($"##color_text", ref textColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf); - ImGui.EndDisabled(); - - _uiSharedService.DrawNoteLine("- ", UIColors.Get("LightlessPurple"), "Glow Color"); - ImGui.SameLine(colorPickAlign); - ImGui.Checkbox("##toggleGlowColor", ref glowEnabled); - ImGui.SameLine(); - ImGui.BeginDisabled(!glowEnabled); - ImGui.ColorEdit4($"##color_glow", ref glowColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf); - ImGui.EndDisabled(); - - bool changed = !Equals(_savedVanity, new VanityState(textEnabled, glowEnabled, textColor, glowColor)); - - if (!changed) - ImGui.BeginDisabled(); - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Changes")) - { - string? newText = textEnabled ? UIColors.RgbaToHex(textColor) : string.Empty; - string? newGlow = glowEnabled ? UIColors.RgbaToHex(glowColor) : string.Empty; - - _ = _apiController.UserUpdateVanityColors(new UserVanityColorsDto(newText, newGlow)); - - _savedVanity = new VanityState(textEnabled, glowEnabled, textColor, glowColor); - } - - if (!changed) - ImGui.EndDisabled(); - - ImGui.Dummy(new Vector2(5)); - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); - - if (!hasVanity) - ImGui.EndDisabled(); - + DrawVanityTabContent(scale); ImGui.EndTabItem(); } ImGui.EndTabBar(); } + ImGui.PopStyleVar(2); + } + + private void DrawProfileTabContent(LightlessUserProfileData profile, float scale) + { + if (profile.IsFlagged) + { + DrawSection("Moderation Status", scale, () => + { + UiSharedService.ColorTextWrapped(profile.Description, ImGuiColors.DalamudRed); + }); + return; + } + + SyncProfileState(profile); + + DrawSection("Profile Preview", scale, () => DrawProfileSnapshot(profile, scale)); + DrawSection("Profile Image", scale, () => DrawProfileImageControls(profile, scale)); + DrawSection("Profile Banner", scale, () => DrawProfileBannerControls(profile, scale)); + DrawSection("Profile Description", scale, () => DrawProfileDescriptionEditor(profile, scale)); + DrawSection("Profile Tags", scale, () => DrawProfileTagsEditor(profile, scale)); + DrawSection("Visibility", scale, () => DrawProfileVisibilityControls(profile)); + } + + private void DrawProfileSnapshot(LightlessUserProfileData profile, float scale) + { + var bannerHeight = 140f * scale; + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##ProfileBannerPreview", new Vector2(-1f, bannerHeight), true)) + { + if (_bannerTextureWrap != null) + { + var childSize = ImGui.GetWindowSize(); + var padding = ImGui.GetStyle().WindowPadding; + var contentSize = new Vector2( + MathF.Max(childSize.X - padding.X * 2f, 1f), + MathF.Max(childSize.Y - padding.Y * 2f, 1f)); + + var imageSize = ImGuiHelpers.ScaledVector2(_bannerTextureWrap.Width, _bannerTextureWrap.Height); + if (imageSize.X > contentSize.X || imageSize.Y > contentSize.Y) + { + var ratio = MathF.Min(contentSize.X / MathF.Max(imageSize.X, 1f), contentSize.Y / MathF.Max(imageSize.Y, 1f)); + imageSize *= ratio; + } + + var offset = new Vector2( + MathF.Max((contentSize.X - imageSize.X) * 0.5f, 0f), + MathF.Max((contentSize.Y - imageSize.Y) * 0.5f, 0f)); + ImGui.SetCursorPos(padding + offset); + ImGui.Image(_bannerTextureWrap.Handle, imageSize); + } + else + { + ImGui.TextColored(UIColors.Get("LightlessPurple"), "No Profile Banner"); + } + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + + ImGui.Dummy(new Vector2(0f, 6f * scale)); + + if (_pfpTextureWrap != null) + { + var size = ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height); + var maxEdge = 150f * scale; + if (size.X > maxEdge || size.Y > maxEdge) + { + var ratio = MathF.Min(maxEdge / MathF.Max(size.X, 1f), maxEdge / MathF.Max(size.Y, 1f)); + size *= ratio; + } + + ImGui.Image(_pfpTextureWrap.Handle, size); + } + else + { + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##ProfileImagePlaceholder", new Vector2(150f * scale, 150f * scale), true)) + ImGui.TextColored(UIColors.Get("LightlessPurple"), "No Profile Picture"); + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + ImGui.Dummy(new Vector2(0f, 4f * scale)); + using (_uiSharedService.GameFont.Push()) + { + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##CurrentProfileDescription", new Vector2(-1f, 120f * scale), true)) + { + ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); + if (string.IsNullOrWhiteSpace(profile.Description)) + { + ImGui.TextDisabled("-- No description --"); + } + else if (!SeStringUtils.TryRenderSeStringMarkupAtCursor(profile.Description!)) + { + UiSharedService.TextWrapped(profile.Description); + } + ImGui.PopTextWrapPos(); + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + ImGui.Dummy(new Vector2(0f, 4f * scale)); + ImGui.TextColored(UIColors.Get("LightlessBlue"), "Saved Tags"); + var savedTags = _profileTagService.ResolveTags(_profileTagIds); + if (savedTags.Count == 0) + { + ImGui.TextDisabled("-- No tags set --"); + } + else + { + bool first = true; + for (int i = 0; i < savedTags.Count; i++) + { + if (!savedTags[i].HasContent) + continue; + + if (!first) + ImGui.SameLine(0f, 6f * scale); + first = false; + using (ImRaii.PushId($"snapshot-tag-{i}")) + DrawTagPreview(savedTags[i], scale, "##snapshotTagPreview"); + } + if (!first) + ImGui.NewLine(); + } + } + + private void DrawProfileImageControls(LightlessUserProfileData profile, float scale) + { + _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "Profile pictures must be 512x512 and under 2 MiB."); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture")) + { + var existingBanner = GetCurrentProfileBannerBase64(profile); + _fileDialogManager.OpenFileDialog("Select new Profile picture", ImageFileDialogFilter, (success, file) => + { + if (!success) return; + _ = Task.Run(async () => + { + var fileContent = File.ReadAllBytes(file); + using MemoryStream ms = new(fileContent); + var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false); + if (!IsSupportedImageFormat(format)) + { + _showProfileImageError = true; + return; + } + + using var image = Image.Load(fileContent); + if (image.Width > 512 || image.Height > 512 || fileContent.Length > 2000 * 1024) + { + _showProfileImageError = true; + return; + } + + _showProfileImageError = false; + var currentTags = GetServerTagPayload(); + _queuedProfileImage = fileContent; + await _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: Convert.ToBase64String(fileContent), + BannerPictureBase64: existingBanner, + Description: null, + Tags: currentTags)).ConfigureAwait(false); + }); + }); + } + UiSharedService.AttachToolTip("Select an image up to 512x512 pixels and <= 2 MiB (PNG/JPG/JPEG/WEBP/BMP)."); + + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear profile picture")) + { + _ = _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: string.Empty, + BannerPictureBase64: GetCurrentProfileBannerBase64(profile), + Description: null, + Tags: GetServerTagPayload())); + } + UiSharedService.AttachToolTip("Remove your current profile picture."); + + if (_showProfileImageError) + { + UiSharedService.ColorTextWrapped("Your profile picture must be no larger than 512x512 pixels and under 2 MiB.", ImGuiColors.DalamudRed); + } + } + + private void DrawProfileBannerControls(LightlessUserProfileData profile, float scale) + { + _uiSharedService.DrawNoteLine("# ", UIColors.Get("LightlessBlue"), "Profile banners must be 840x260 and under 2 MiB."); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile banner")) + { + var existingProfile = GetCurrentProfilePictureBase64(profile); + _fileDialogManager.OpenFileDialog("Select new Profile banner", ImageFileDialogFilter, (success, file) => + { + if (!success) return; + _ = Task.Run(async () => + { + var fileContent = File.ReadAllBytes(file); + using MemoryStream ms = new(fileContent); + var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false); + if (!IsSupportedImageFormat(format)) + { + _showBannerImageError = true; + return; + } + + using var image = Image.Load(fileContent); + if (image.Width > 840 || image.Height > 260 || fileContent.Length > 2000 * 1024) + { + _showBannerImageError = true; + return; + } + + _showBannerImageError = false; + var currentTags = GetServerTagPayload(); + await _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: existingProfile, + BannerPictureBase64: Convert.ToBase64String(fileContent), + Description: null, + Tags: currentTags)).ConfigureAwait(false); + }); + }); + } + UiSharedService.AttachToolTip("Select an image up to 840x260 pixels and <= 2 MiB (PNG/JPG/JPEG/WEBP/BMP)."); + + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear profile banner")) + { + _ = _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: GetCurrentProfilePictureBase64(profile), + BannerPictureBase64: string.Empty, + Description: null, + Tags: GetServerTagPayload())); + } + UiSharedService.AttachToolTip("Remove your current profile banner."); + + if (_showBannerImageError) + { + UiSharedService.ColorTextWrapped("Your banner image must be no larger than 840x260 pixels and under 2 MiB.", ImGuiColors.DalamudRed); + } + } + + private void DrawProfileDescriptionEditor(LightlessUserProfileData profile, float scale) + { + ImGui.TextUnformatted($"Description {_descriptionText.Length}/1500"); + ImGui.SameLine(); + ImGuiComponents.HelpMarker(DescriptionMacroTooltip); + using (_uiSharedService.GameFont.Push()) + { + var inputSize = new Vector2(-1f, 160f * scale); + ImGui.InputTextMultiline("##profileDescriptionInput", ref _descriptionText, 1500, inputSize); + } + + ImGui.Dummy(new Vector2(0f, 3f * scale)); + ImGui.TextColored(UIColors.Get("LightlessBlue"), "Preview"); + using (_uiSharedService.GameFont.Push()) + { + ImGui.PushStyleVar(ImGuiStyleVar.ChildRounding, 4f * scale); + if (ImGui.BeginChild("##profileDescriptionPreview", new Vector2(-1f, 140f * scale), true)) + { + ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); + if (string.IsNullOrWhiteSpace(_descriptionText)) + { + ImGui.TextDisabled("-- Description preview --"); + } + else if (!SeStringUtils.TryRenderSeStringMarkupAtCursor(_descriptionText)) + { + UiSharedService.TextWrapped(_descriptionText); + } + ImGui.PopTextWrapPos(); + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + ImGui.Dummy(new Vector2(0f, 4f * scale)); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description")) + { + _ = _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: GetCurrentProfilePictureBase64(profile), + BannerPictureBase64: GetCurrentProfileBannerBase64(profile), + _descriptionText, + Tags: GetServerTagPayload())); + } + UiSharedService.AttachToolTip("Apply the text above to your profile."); + + ImGui.SameLine(); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description")) + { + _descriptionText = string.Empty; + _ = _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: GetCurrentProfilePictureBase64(profile), + BannerPictureBase64: GetCurrentProfileBannerBase64(profile), + Description: string.Empty, + Tags: GetServerTagPayload())); + } + UiSharedService.AttachToolTip("Remove the description from your profile."); + } + + private void DrawProfileTagsEditor(LightlessUserProfileData profile, float scale) + { + DrawTagEditor( + scale, + contextPrefix: "user", + saveTooltip: "Apply the selected tags to your profile.", + submitAction: payload => _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + IsNSFW: null, + ProfilePictureBase64: GetCurrentProfilePictureBase64(profile), + BannerPictureBase64: GetCurrentProfileBannerBase64(profile), + Description: null, + Tags: payload)), + allowReorder: true, + sortPayloadBeforeSubmit: false); + } + + private void DrawTagEditor( + float scale, + string contextPrefix, + string saveTooltip, + Func submitAction, + bool allowReorder, + bool sortPayloadBeforeSubmit, + Action? onPayloadPrepared = null) + { + var tagLibrary = _profileTagService.GetTagLibrary(); + if (tagLibrary.Count == 0) + { + ImGui.TextDisabled("No profile tags are available."); + return; + } + + var style = ImGui.GetStyle(); + var defaultTextColorU32 = ImGui.GetColorU32(ImGuiCol.Text); + + var selectedCount = _tagEditorSelection.Count; + ImGui.TextColored(UIColors.Get("LightlessBlue"), $"Selected Tags ({selectedCount}/{MaxProfileTags})"); + + int? tagToRemove = null; + int? moveUpRequest = null; + int? moveDownRequest = null; + + if (selectedCount == 0) + { + ImGui.TextDisabled("-- No tags selected --"); + } + else + { + var selectedFlags = ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.SizingStretchSame; + var selectedTableId = $"##{contextPrefix}SelectedTagsTable"; + var columnCount = allowReorder ? 3 : 2; + + if (ImGui.BeginTable(selectedTableId, columnCount, selectedFlags)) + { + ImGui.TableSetupColumn("Preview", ImGuiTableColumnFlags.WidthStretch, allowReorder ? 0.55f : 0.75f); + if (allowReorder) + ImGui.TableSetupColumn("##order", ImGuiTableColumnFlags.WidthStretch, 0.1f); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 90f); + ImGui.TableHeadersRow(); + + for (int i = 0; i < _tagEditorSelection.Count; i++) + { + var tagId = _tagEditorSelection[i]; + if (!tagLibrary.TryGetValue(tagId, out var definition) || !definition.HasContent) + continue; + + var displayName = GetTagDisplayName(definition, tagId); + var idLabel = $"ID {tagId}"; + var previewSize = ProfileTagRenderer.MeasureTag(definition, scale, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _tagPreviewSegments, ResolveIconWrap, _logger); + var textHeight = ImGui.CalcTextSize(displayName).Y + style.ItemSpacing.Y + ImGui.CalcTextSize(idLabel).Y; + var rowHeight = MathF.Max(previewSize.Y + style.CellPadding.Y * 2f, textHeight + style.CellPadding.Y * 2f); + + ImGui.TableNextRow(ImGuiTableRowFlags.None, rowHeight); + ImGui.TableNextColumn(); + using (ImRaii.PushId($"{contextPrefix}-selected-tag-{tagId}-{i}")) + DrawCenteredTagCell(definition, scale, previewSize, rowHeight, defaultTextColorU32); + if (ImGui.IsItemHovered()) + { + ImGui.BeginTooltip(); + ImGui.TextUnformatted(displayName); + ImGui.TextDisabled(idLabel); + ImGui.EndTooltip(); + } + + if (allowReorder) + { + ImGui.TableNextColumn(); + DrawReorderCell(contextPrefix, tagId, i, _tagEditorSelection.Count, rowHeight, scale, ref moveUpRequest, ref moveDownRequest); + } + + ImGui.TableNextColumn(); + DrawFullCellButton("Remove", UIColors.Get("DimRed"), ref tagToRemove, tagId, false, scale, rowHeight, $"{contextPrefix}-remove-{tagId}-{i}"); + } + + ImGui.EndTable(); + } + } + + if (allowReorder) + { + if (moveUpRequest.HasValue && moveUpRequest.Value > 0) + { + var idx = moveUpRequest.Value; + (_tagEditorSelection[idx - 1], _tagEditorSelection[idx]) = (_tagEditorSelection[idx], _tagEditorSelection[idx - 1]); + } + + if (moveDownRequest.HasValue && moveDownRequest.Value < _tagEditorSelection.Count - 1) + { + var idx = moveDownRequest.Value; + (_tagEditorSelection[idx], _tagEditorSelection[idx + 1]) = (_tagEditorSelection[idx + 1], _tagEditorSelection[idx]); + } + } + + if (tagToRemove.HasValue) + _tagEditorSelection.Remove(tagToRemove.Value); + + bool limitReached = _tagEditorSelection.Count >= MaxProfileTags; + if (limitReached) + UiSharedService.ColorTextWrapped($"You have reached the maximum of {MaxProfileTags} tags. Remove one before adding more.", UIColors.Get("DimRed")); + + ImGui.Dummy(new Vector2(0f, 6f * scale)); + ImGui.TextColored(UIColors.Get("LightlessPurple"), "Available Tags"); + + var availableIds = new List(tagLibrary.Count); + var seenDefinitions = new HashSet(); + foreach (var kvp in tagLibrary) + { + var definition = kvp.Value; + if (!definition.HasContent) + continue; + + if (!seenDefinitions.Add(definition)) + continue; + + if (_tagEditorSelection.Contains(kvp.Key)) + continue; + + availableIds.Add(kvp.Key); + } + + availableIds.Sort(); + int totalAvailable = availableIds.Count; + if (totalAvailable == 0) + { + ImGui.TextDisabled("-- No additional tags available --"); + } + else + { + int pageCount = Math.Max(1, (totalAvailable + AvailableTagsPerPage - 1) / AvailableTagsPerPage); + _availableTagPage = Math.Clamp(_availableTagPage, 0, pageCount - 1); + int start = _availableTagPage * AvailableTagsPerPage; + int end = Math.Min(totalAvailable, start + AvailableTagsPerPage); + + ImGui.SameLine(); + ImGui.TextDisabled($"Page {_availableTagPage + 1}/{pageCount}"); + ImGui.SameLine(); + ImGui.BeginDisabled(_availableTagPage == 0); + if (ImGui.SmallButton($"<##{contextPrefix}TagPagePrev")) + _availableTagPage--; + ImGui.EndDisabled(); + ImGui.SameLine(); + ImGui.BeginDisabled(_availableTagPage >= pageCount - 1); + if (ImGui.SmallButton($">##{contextPrefix}TagPageNext")) + _availableTagPage++; + ImGui.EndDisabled(); + + var availableFlags = ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.SizingStretchSame; + int? tagToAdd = null; + + if (ImGui.BeginTable($"##{contextPrefix}AvailableTagsTable", 2, availableFlags)) + { + ImGui.TableSetupColumn("Preview", ImGuiTableColumnFlags.WidthStretch, 0.75f); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 90f); + ImGui.TableHeadersRow(); + + for (int idx = start; idx < end; idx++) + { + var tagId = availableIds[idx]; + if (!tagLibrary.TryGetValue(tagId, out var definition) || !definition.HasContent) + continue; + + var previewSize = ProfileTagRenderer.MeasureTag(definition, scale, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _tagPreviewSegments, ResolveIconWrap, _logger); + var rowHeight = previewSize.Y + style.CellPadding.Y * 2f; + + ImGui.TableNextRow(ImGuiTableRowFlags.None, rowHeight); + ImGui.TableNextColumn(); + using (ImRaii.PushId($"{contextPrefix}-available-tag-{tagId}")) + DrawCenteredTagCell(definition, scale, previewSize, rowHeight, defaultTextColorU32); + if (ImGui.IsItemHovered()) + { + var name = GetTagDisplayName(definition, tagId); + ImGui.BeginTooltip(); + ImGui.TextUnformatted(name); + ImGui.TextDisabled($"ID {tagId}"); + ImGui.EndTooltip(); + } + + ImGui.TableNextColumn(); + DrawFullCellButton("Add", UIColors.Get("LightlessGreen"), ref tagToAdd, tagId, limitReached, scale, rowHeight, $"{contextPrefix}-add-{tagId}"); + } + + ImGui.EndTable(); + } + + if (tagToAdd.HasValue) + { + _tagEditorSelection.Add(tagToAdd.Value); + if (_availableTagPage > 0 && (totalAvailable - 1) <= start) + _availableTagPage = Math.Max(0, _availableTagPage - 1); + } + } + + bool hasChanges = !TagsEqual(_tagEditorSelection, _profileTagIds); + ImGui.Dummy(new Vector2(0f, 6f * scale)); + if (!hasChanges) + ImGui.BeginDisabled(); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, $"Save Tags##{contextPrefix}")) + { + var payload = _tagEditorSelection.Count == 0 ? Array.Empty() : _tagEditorSelection.ToArray(); + if (sortPayloadBeforeSubmit && payload.Length > 1) + Array.Sort(payload); + onPayloadPrepared?.Invoke(payload); + _ = submitAction(payload); + } + + if (!hasChanges) + ImGui.EndDisabled(); + + UiSharedService.AttachToolTip(saveTooltip); + } + + private void DrawProfileVisibilityControls(LightlessUserProfileData profile) + { + var isNsfw = profile.IsNSFW; + if (DrawCheckboxRow("Mark profile as NSFW", isNsfw, out var newValue, "Enable when your profile could be considered NSFW.")) + { + _ = _apiController.UserSetProfile(new UserProfileDto( + new UserData(_apiController.UID), + Disabled: false, + newValue, + ProfilePictureBase64: GetCurrentProfilePictureBase64(profile), + Description: null, + BannerPictureBase64: GetCurrentProfileBannerBase64(profile), + Tags: GetServerTagPayload())); + } + + } + + private string? GetCurrentProfilePictureBase64(LightlessUserProfileData profile) + { + if (_queuedProfileImage is { Length: > 0 }) + return Convert.ToBase64String(_queuedProfileImage); + + if (!string.IsNullOrWhiteSpace(profile.Base64ProfilePicture) && !string.Equals(profile.Description, LoadingProfileDescription, StringComparison.Ordinal)) + return profile.Base64ProfilePicture; + + return _profileImage.Length > 0 ? Convert.ToBase64String(_profileImage) : null; + } + + private string? GetCurrentProfileBannerBase64(LightlessUserProfileData profile) + { + if (!string.IsNullOrWhiteSpace(profile.Base64BannerPicture) && !string.Equals(profile.Description, LoadingProfileDescription, StringComparison.Ordinal)) + return profile.Base64BannerPicture; + + return _bannerImage.Length > 0 ? Convert.ToBase64String(_bannerImage) : null; + } + + private void DrawTagPreview(ProfileTagDefinition tag, float scale, string id) + { + var style = ImGui.GetStyle(); + var defaultTextColorU32 = ImGui.GetColorU32(ImGuiCol.Text); + var tagSize = ProfileTagRenderer.MeasureTag(tag, scale, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _tagPreviewSegments, ResolveIconWrap, _logger); + + ImGui.InvisibleButton(id, tagSize); + var rectMin = ImGui.GetItemRectMin(); + var drawList = ImGui.GetWindowDrawList(); + ProfileTagRenderer.RenderTag(tag, rectMin, scale, drawList, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _tagPreviewSegments, ResolveIconWrap, _logger); + } + + private static bool IsSupportedImageFormat(IImageFormat? format) + { + if (format is null) + return false; + + foreach (var ext in format.FileExtensions) + { + if (SupportedImageExtensions.Contains(ext)) + return true; + } + + return false; + } + + private void DrawCenteredTagCell(ProfileTagDefinition tag, float scale, Vector2 tagSize, float rowHeight, uint defaultTextColorU32) + { + var style = ImGui.GetStyle(); + var cellStart = ImGui.GetCursorPos(); + var available = ImGui.GetContentRegionAvail(); + var innerHeight = MathF.Max(0f, rowHeight - style.CellPadding.Y * 2f); + var offsetX = MathF.Max(0f, (available.X - tagSize.X) * 0.5f); + var offsetY = MathF.Max(0f, innerHeight - tagSize.Y) * 0.5f; + + ImGui.SetCursorPos(new Vector2(cellStart.X + offsetX, cellStart.Y + style.CellPadding.Y + offsetY)); + ImGui.InvisibleButton("##tagPreview", tagSize); + var rectMin = ImGui.GetItemRectMin(); + var drawList = ImGui.GetWindowDrawList(); + ProfileTagRenderer.RenderTag(tag, rectMin, scale, drawList, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _tagPreviewSegments, ResolveIconWrap, _logger); + } + + private void DrawInfoCell(string displayName, string idLabel, float rowHeight, ImGuiStylePtr style) + { + var cellStart = ImGui.GetCursorPos(); + var nameSize = ImGui.CalcTextSize(displayName); + var idSize = ImGui.CalcTextSize(idLabel); + var totalHeight = nameSize.Y + style.ItemSpacing.Y + idSize.Y; + var offsetY = MathF.Max(0f, (rowHeight - totalHeight) * 0.5f) - style.CellPadding.Y; + if (offsetY < 0f) offsetY = 0f; + + ImGui.SetCursorPos(new Vector2(cellStart.X + style.CellPadding.X, cellStart.Y + offsetY)); + ImGui.TextUnformatted(displayName); + ImGui.SetCursorPos(new Vector2(cellStart.X + style.CellPadding.X, ImGui.GetCursorPosY() + style.ItemSpacing.Y)); + ImGui.TextDisabled(idLabel); + } + + private void DrawReorderCell( + string contextPrefix, + int tagId, + int index, + int count, + float rowHeight, + float scale, + ref int? moveUpTarget, + ref int? moveDownTarget) + { + var style = ImGui.GetStyle(); + var cellStart = ImGui.GetCursorPos(); + var availableWidth = ImGui.GetContentRegionAvail().X; + var innerHeight = MathF.Max(0f, rowHeight - style.CellPadding.Y * 2f); + var spacing = MathF.Min(style.ItemSpacing.Y * 0.5f, innerHeight * 0.15f); + var buttonHeight = MathF.Max(1f, (innerHeight - spacing) * 0.5f); + var width = MathF.Max(1f, availableWidth); + + var upColor = UIColors.Get("LightlessBlue"); + using (ImRaii.PushId($"{contextPrefix}-order-{tagId}-{index}")) + { + ImGui.SetCursorPos(new Vector2(cellStart.X, cellStart.Y + style.CellPadding.Y)); + if (ColoredButton("\u2191##tagMoveUp", upColor, new Vector2(width, buttonHeight), scale, index == 0)) + moveUpTarget = index; + + ImGui.SetCursorPos(new Vector2(cellStart.X, cellStart.Y + style.CellPadding.Y + buttonHeight + spacing)); + if (ColoredButton("\u2193##tagMoveDown", upColor, new Vector2(width, buttonHeight), scale, index >= count - 1)) + moveDownTarget = index; + } + } + + private void DrawFullCellButton(string label, Vector4 baseColor, ref int? target, int tagId, bool disabled, float scale, float rowHeight, string idSuffix) + { + var style = ImGui.GetStyle(); + var cellStart = ImGui.GetCursorPos(); + var available = ImGui.GetContentRegionAvail(); + var buttonHeight = MathF.Max(1f, rowHeight - style.CellPadding.Y * 2f); + var hovered = BlendTowardsWhite(baseColor, 0.15f); + var active = BlendTowardsWhite(baseColor, 0.3f); + + ImGui.SetCursorPos(new Vector2(cellStart.X, cellStart.Y + style.CellPadding.Y)); + using (ImRaii.PushId(idSuffix)) + { + if (ColoredButton(label, baseColor, new Vector2(MathF.Max(available.X, 1f), buttonHeight), scale, disabled)) + target = tagId; + } + } + + private bool ColoredButton(string label, Vector4 baseColor, Vector2 size, float scale, bool disabled) + { + var style = ImGui.GetStyle(); + var hovered = BlendTowardsWhite(baseColor, 0.15f); + var active = BlendTowardsWhite(baseColor, 0.3f); + + ImGui.PushStyleColor(ImGuiCol.Button, baseColor); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hovered); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, active); + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, style.FrameRounding); + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(MathF.Max(2f, style.FramePadding.X), MathF.Max(1f, style.FramePadding.Y * 0.3f)) * scale); + + ImGui.BeginDisabled(disabled); + bool clicked = ImGui.Button(label, size); + ImGui.EndDisabled(); + + ImGui.PopStyleVar(2); + ImGui.PopStyleColor(3); + + return clicked; + } + + private static float Clamp01(float value) + => value < 0f ? 0f : value > 1f ? 1f : value; + + private static Vector4 BlendTowardsWhite(Vector4 color, float amount) + { + var result = Vector4.Lerp(color, Vector4.One, Clamp01(amount)); + result.W = color.W; + return result; + } + + private static string GetTagDisplayName(ProfileTagDefinition tag, int tagId) + { + if (!string.IsNullOrWhiteSpace(tag.Text)) + return tag.Text!; + + if (!string.IsNullOrWhiteSpace(tag.SeStringPayload)) + { + var stripped = SeStringUtils.StripMarkup(tag.SeStringPayload!); + if (!string.IsNullOrWhiteSpace(stripped)) + return stripped; + } + + return $"Tag {tagId}"; + } + + private IDalamudTextureWrap? ResolveIconWrap(uint iconId) + { + if (_uiSharedService.TryGetIcon(iconId, out var wrap) && wrap != null) + return wrap; + return null; + } + + private int[] GetServerTagPayload() + { + if (_profileTagIds.Length == 0) + return Array.Empty(); + + var copy = new int[_profileTagIds.Length]; + Array.Copy(_profileTagIds, copy, _profileTagIds.Length); + return copy; + } + + private static bool TagsEqual(IReadOnlyList? current, IReadOnlyList? reference) + { + if (ReferenceEquals(current, reference)) + return true; + if (current is null || reference is null) + return false; + if (current.Count != reference.Count) + return false; + + for (int i = 0; i < current.Count; i++) + { + if (current[i] != reference[i]) + return false; + } + + return true; + } + + private void DrawVanityTabContent(float scale) + { + DrawSection("Colored UID", scale, () => + { + var hasVanity = _apiController.HasVanity; + if (!hasVanity) + { + UiSharedService.ColorTextWrapped("You do not currently have vanity access. Become a supporter to unlock these features. (If you already are, interact with the bot to update)", UIColors.Get("DimRed")); + } + + var monoFont = UiBuilder.MonoFont; + using (ImRaii.PushFont(monoFont)) + { + var previewTextColor = textEnabled ? textColor : Vector4.One; + var previewGlowColor = glowEnabled ? glowColor : Vector4.Zero; + var seString = SeStringUtils.BuildFormattedPlayerName(_apiController.DisplayName, previewTextColor, previewGlowColor); + + var drawList = ImGui.GetWindowDrawList(); + var textSize = ImGui.CalcTextSize(seString.TextValue); + float minWidth = 160f * ImGuiHelpers.GlobalScale; + float bgWidth = Math.Max(textSize.X + 20f * ImGuiHelpers.GlobalScale, minWidth); + float paddingY = 5f * ImGuiHelpers.GlobalScale; + + var cursor = ImGui.GetCursorScreenPos(); + var rectMin = cursor; + var rectMax = rectMin + new Vector2(bgWidth, textSize.Y + paddingY * 2f); + + float boost = Luminance.ComputeHighlight(previewTextColor, previewGlowColor); + + var baseBg = new Vector4(0.15f + boost, 0.15f + boost, 0.15f + boost, 1f); + var bgColor = Luminance.BackgroundContrast(previewTextColor, previewGlowColor, baseBg, ref _currentBg); + var borderColor = UIColors.Get("LightlessPurple"); + + drawList.AddRectFilled(rectMin, rectMax, ImGui.GetColorU32(bgColor), 5f); + drawList.AddRect(rectMin, rectMax, ImGui.GetColorU32(borderColor), 5f, ImDrawFlags.None, 1.2f); + + var textPos = new Vector2(rectMin.X + (bgWidth - textSize.X) * 0.5f, rectMin.Y + paddingY); + SeStringUtils.RenderSeStringWithHitbox(seString, textPos, monoFont); + + ImGui.Dummy(new Vector2(0f, 1.5f)); + } + + ImGui.TextColored(UIColors.Get("LightlessPurple"), "Colors"); + if (!hasVanity) + ImGui.BeginDisabled(); + + if (DrawCheckboxRow("Enable custom text color", textEnabled, out var newTextEnabled)) + textEnabled = newTextEnabled; + + ImGui.SameLine(); + ImGui.BeginDisabled(!textEnabled); + ImGui.ColorEdit4("Text Color##vanityTextColor", ref textColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf); + ImGui.EndDisabled(); + + if (DrawCheckboxRow("Enable glow color", glowEnabled, out var newGlowEnabled)) + glowEnabled = newGlowEnabled; + + ImGui.SameLine(); + ImGui.BeginDisabled(!glowEnabled); + ImGui.ColorEdit4("Glow Color##vanityGlowColor", ref glowColor, ImGuiColorEditFlags.NoInputs | ImGuiColorEditFlags.AlphaPreviewHalf); + ImGui.EndDisabled(); + + bool changed = !Equals(_savedVanity, new VanityState(textEnabled, glowEnabled, textColor, glowColor)); + if (!changed) + ImGui.BeginDisabled(); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Vanity Changes")) + { + string? newText = textEnabled ? UIColors.RgbaToHex(textColor) : string.Empty; + string? newGlow = glowEnabled ? UIColors.RgbaToHex(glowColor) : string.Empty; + + _ = _apiController.UserUpdateVanityColors(new UserVanityColorsDto(newText, newGlow)); + _savedVanity = new VanityState(textEnabled, glowEnabled, textColor, glowColor); + } + + if (!changed) + ImGui.EndDisabled(); + + if (!hasVanity) + ImGui.EndDisabled(); + }); + } + + private void DrawSection(string title, float scale, Action body) + { + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(6f, 4f) * scale); + + var flags = ImGuiTreeNodeFlags.SpanFullWidth | ImGuiTreeNodeFlags.Framed | ImGuiTreeNodeFlags.AllowItemOverlap | ImGuiTreeNodeFlags.DefaultOpen; + var open = ImGui.CollapsingHeader(title, flags); + ImGui.PopStyleVar(); + + if (open) + { + ImGui.Dummy(new Vector2(0f, 3f * scale)); + body(); + ImGui.Dummy(new Vector2(0f, 2f * scale)); + } + } + + private bool DrawCheckboxRow(string label, bool currentValue, out bool newValue, string? tooltip = null) + { + + bool value = currentValue; + bool changed = UiSharedService.CheckboxWithBorder(label, ref value, UIColors.Get("LightlessPurple"), 1.5f); + if (!string.IsNullOrEmpty(tooltip)) + UiSharedService.AttachToolTip(tooltip); + + newValue = value; + return changed; + } + + private void SyncProfileState(LightlessUserProfileData profile) + { + if (string.Equals(profile.Description, LoadingProfileDescription, StringComparison.Ordinal)) + return; + + var profileBytes = profile.ImageData.Value; + if (_pfpTextureWrap == null || !_profileImage.SequenceEqual(profileBytes)) + { + _profileImage = profileBytes; + _pfpTextureWrap?.Dispose(); + _pfpTextureWrap = _profileImage.Length > 0 ? _uiSharedService.LoadImage(_profileImage) : null; + _queuedProfileImage = null; + } + + var bannerBytes = profile.BannerImageData.Value; + if (_bannerTextureWrap == null || !_bannerImage.SequenceEqual(bannerBytes)) + { + _bannerImage = bannerBytes; + _bannerTextureWrap?.Dispose(); + _bannerTextureWrap = _bannerImage.Length > 0 ? _uiSharedService.LoadImage(_bannerImage) : null; + } + + if (!string.Equals(_profileDescription, profile.Description, StringComparison.Ordinal)) + { + _profileDescription = profile.Description; + _descriptionText = _profileDescription; + } + + var serverTags = profile.Tags ?? Array.Empty(); + if (!TagsEqual(serverTags, _profileTagIds)) + { + var previous = _profileTagIds; + _profileTagIds = serverTags.Count == 0 ? Array.Empty() : serverTags.ToArray(); + + if (TagsEqual(_tagEditorSelection, previous)) + { + _tagEditorSelection.Clear(); + if (_profileTagIds.Length > 0) + _tagEditorSelection.AddRange(_profileTagIds); + } + } + } + + private static bool IsWindowBeingDragged() + { + return ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows) && ImGui.GetIO().MouseDown[0]; } protected override void Dispose(bool disposing) { base.Dispose(disposing); _pfpTextureWrap?.Dispose(); + _bannerTextureWrap?.Dispose(); } } \ No newline at end of file diff --git a/LightlessSync/UI/Handlers/IdDisplayHandler.cs b/LightlessSync/UI/Handlers/IdDisplayHandler.cs index 4d362a9..0d45938 100644 --- a/LightlessSync/UI/Handlers/IdDisplayHandler.cs +++ b/LightlessSync/UI/Handlers/IdDisplayHandler.cs @@ -10,13 +10,16 @@ using LightlessSync.Services.ServerConfiguration; using LightlessSync.UI.Style; using LightlessSync.Utils; using System; +using System.Collections.Generic; using System.Numerics; +using System.Text; namespace LightlessSync.UI.Handlers; public class IdDisplayHandler { private readonly LightlessConfigService _lightlessConfigService; + private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private readonly LightlessMediator _mediator; private readonly ServerConfigurationManager _serverManager; private readonly Dictionary _showIdForEntry = new(StringComparer.Ordinal); @@ -30,11 +33,16 @@ public class IdDisplayHandler private Vector4 _currentBg = new(0.15f, 0.15f, 0.15f, 1f); private float _highlightBoost; - public IdDisplayHandler(LightlessMediator mediator, ServerConfigurationManager serverManager, LightlessConfigService lightlessConfigService) + public IdDisplayHandler( + LightlessMediator mediator, + ServerConfigurationManager serverManager, + LightlessConfigService lightlessConfigService, + PlayerPerformanceConfigService playerPerformanceConfigService) { _mediator = mediator; _serverManager = serverManager; _lightlessConfigService = lightlessConfigService; + _playerPerformanceConfigService = playerPerformanceConfigService; } public void DrawGroupText(string id, GroupFullInfoDto group, float textPosX, Func editBoxWidth) @@ -48,6 +56,13 @@ public class IdDisplayHandler using (ImRaii.PushFont(UiBuilder.MonoFont, textIsUid)) ImGui.TextUnformatted(playerText); + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Left click to switch between ID display and alias" + + Environment.NewLine + "Right click to edit notes for this syncshell" + + Environment.NewLine + "Middle Mouse Button to open syncshell profile in a separate window"); + } + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) { var prevState = textIsUid; @@ -73,6 +88,11 @@ public class IdDisplayHandler _editEntry = group.GID; _editIsUid = false; } + + if (ImGui.IsItemClicked(ImGuiMouseButton.Middle)) + { + _mediator.Publish(new GroupProfileOpenStandaloneMessage(group)); + } } else { @@ -97,10 +117,14 @@ public class IdDisplayHandler { ImGui.SameLine(textPosX); (bool textIsUid, string playerText) = GetPlayerText(pair); + var compactPerformanceText = BuildCompactPerformanceUsageText(pair); if (!string.Equals(_editEntry, pair.UserData.UID, StringComparison.Ordinal)) { ImGui.AlignTextToFramePadding(); + var rowStart = ImGui.GetCursorScreenPos(); + var rowWidth = MathF.Max(editBoxWidth.Invoke(), 0f); + var rowRightLimit = rowStart.X + rowWidth; var font = textIsUid ? UiBuilder.MonoFont : ImGui.GetFont(); @@ -125,7 +149,6 @@ public class IdDisplayHandler ? SeStringUtils.BuildFormattedPlayerName(playerText, textColor, glowColor) : SeStringUtils.BuildPlain(playerText); - var rowStart = ImGui.GetCursorScreenPos(); var drawList = ImGui.GetWindowDrawList(); bool useHighlight = false; float highlightPadX = 0f; @@ -200,6 +223,8 @@ public class IdDisplayHandler drawList.ChannelsMerge(); } + var nameRectMin = ImGui.GetItemRectMin(); + var nameRectMax = ImGui.GetItemRectMax(); if (ImGui.IsItemHovered()) { if (!string.Equals(_lastMouseOverUid, id)) @@ -261,12 +286,43 @@ public class IdDisplayHandler { _mediator.Publish(new ProfileOpenStandaloneMessage(pair)); } + + if (!string.IsNullOrEmpty(compactPerformanceText)) + { + ImGui.SameLine(); + + const float compactFontScale = 0.85f; + ImGui.SetWindowFontScale(compactFontScale); + var compactHeight = ImGui.GetTextLineHeight(); + var nameHeight = nameRectMax.Y - nameRectMin.Y; + var targetPos = ImGui.GetCursorScreenPos(); + var availableWidth = MathF.Max(rowRightLimit - targetPos.X, 0f); + var centeredY = nameRectMin.Y + MathF.Max((nameHeight - compactHeight) * 0.5f, 0f); + float verticalOffset = 1f * ImGuiHelpers.GlobalScale; + centeredY += verticalOffset; + ImGui.SetCursorScreenPos(new Vector2(targetPos.X, centeredY)); + + var performanceText = string.Empty; + var wasTruncated = false; + if (availableWidth > 0f) + { + performanceText = TruncateTextToWidth(compactPerformanceText, availableWidth, out wasTruncated); + } + + ImGui.TextDisabled(performanceText); + ImGui.SetWindowFontScale(1f); + + if (wasTruncated && ImGui.IsItemHovered()) + { + ImGui.SetTooltip(compactPerformanceText); + } + } } else { ImGui.AlignTextToFramePadding(); - ImGui.SetNextItemWidth(editBoxWidth.Invoke()); + ImGui.SetNextItemWidth(MathF.Max(editBoxWidth.Invoke(), 0f)); if (ImGui.InputTextWithHint("##" + pair.UserData.UID, "Nick/Notes", ref _editComment, 255, ImGuiInputTextFlags.EnterReturnsTrue)) { _serverManager.SetNoteForUid(pair.UserData.UID, _editComment); @@ -346,6 +402,57 @@ public class IdDisplayHandler return (textIsUid, playerText!); } + private string? BuildCompactPerformanceUsageText(Pair pair) + { + var config = _playerPerformanceConfigService.Current; + if (!config.ShowPerformanceIndicator || !config.ShowPerformanceUsageNextToName) + { + return null; + } + + var vramBytes = pair.LastAppliedApproximateEffectiveVRAMBytes >= 0 + ? pair.LastAppliedApproximateEffectiveVRAMBytes + : pair.LastAppliedApproximateVRAMBytes; + var triangleCount = pair.LastAppliedDataTris; + if (vramBytes < 0 && triangleCount < 0) + { + return null; + } + + var segments = new List(2); + if (vramBytes >= 0) + { + segments.Add(UiSharedService.ByteToString(vramBytes)); + } + + if (triangleCount >= 0) + { + segments.Add(FormatTriangleCount(triangleCount)); + } + + return segments.Count == 0 ? null : string.Join(" / ", segments); + } + + private static string FormatTriangleCount(long triangleCount) + { + if (triangleCount < 0) + { + return string.Empty; + } + + if (triangleCount >= 1_000_000) + { + return FormattableString.Invariant($"{triangleCount / 1_000_000d:0.#}m tris"); + } + + if (triangleCount >= 1_000) + { + return FormattableString.Invariant($"{triangleCount / 1_000d:0.#}k tris"); + } + + return $"{triangleCount} tris"; + } + internal void Clear() { _editEntry = string.Empty; @@ -370,4 +477,52 @@ public class IdDisplayHandler return showidInsteadOfName; } -} \ No newline at end of file + + private static string TruncateTextToWidth(string text, float maxWidth, out bool wasTruncated) + { + wasTruncated = false; + if (string.IsNullOrEmpty(text) || maxWidth <= 0f) + { + return string.Empty; + } + + var fullWidth = ImGui.CalcTextSize(text).X; + if (fullWidth <= maxWidth) + { + return text; + } + + wasTruncated = true; + + const string Ellipsis = "..."; + var ellipsisWidth = ImGui.CalcTextSize(Ellipsis).X; + if (ellipsisWidth >= maxWidth) + { + return Ellipsis; + } + + var builder = new StringBuilder(text.Length); + var remainingWidth = maxWidth - ellipsisWidth; + + foreach (var rune in text.EnumerateRunes()) + { + var runeText = rune.ToString(); + var runeWidth = ImGui.CalcTextSize(runeText).X; + if (runeWidth > remainingWidth) + { + break; + } + + builder.Append(runeText); + remainingWidth -= runeWidth; + } + + if (builder.Length == 0) + { + return Ellipsis; + } + + builder.Append(Ellipsis); + return builder.ToString(); + } +} diff --git a/LightlessSync/UI/Models/PairDisplayEntry.cs b/LightlessSync/UI/Models/PairDisplayEntry.cs new file mode 100644 index 0000000..e89e7fe --- /dev/null +++ b/LightlessSync/UI/Models/PairDisplayEntry.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using LightlessSync.API.Data; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Dto.Group; +using LightlessSync.PlayerData.Pairs; + +namespace LightlessSync.UI.Models; + +public sealed record PairDisplayEntry( + PairUniqueIdentifier Ident, + PairConnection Connection, + IReadOnlyList Groups, + IPairHandlerAdapter? Handler) +{ + public UserData User => Connection.User; + public bool IsOnline => Connection.IsOnline; + public bool IsVisible => Handler?.IsVisible ?? false; + public bool IsDirectlyPaired => Connection.IsDirectlyPaired; + public bool IsOneSided => Connection.IsOneSided; + public bool HasAnyConnection => Connection.HasAnyConnection; + public string? IdentString => Connection.Ident; + public UserPermissions SelfPermissions => Connection.SelfToOtherPermissions; + public UserPermissions OtherPermissions => Connection.OtherToSelfPermissions; + public IndividualPairStatus? PairStatus => Connection.IndividualPairStatus; +} diff --git a/LightlessSync/UI/Models/PairUiEntry.cs b/LightlessSync/UI/Models/PairUiEntry.cs new file mode 100644 index 0000000..c25b6fd --- /dev/null +++ b/LightlessSync/UI/Models/PairUiEntry.cs @@ -0,0 +1,30 @@ +using LightlessSync.API.Data; +using LightlessSync.API.Data.Enum; +using LightlessSync.API.Dto.Group; +using LightlessSync.PlayerData.Pairs; + +namespace LightlessSync.UI.Models; + +public sealed record PairUiEntry( + PairDisplayEntry DisplayEntry, + string AliasOrUid, + string DisplayName, + string Note, + bool IsVisible, + bool IsOnline, + bool IsDirectlyPaired, + bool IsOneSided, + bool HasAnyConnection, + bool IsPaused, + UserPermissions SelfPermissions, + UserPermissions OtherPermissions, + IndividualPairStatus? PairStatus, + long LastAppliedDataBytes, + long LastAppliedDataTris, + long LastAppliedApproximateVramBytes, + long LastAppliedApproximateEffectiveVramBytes, + IPairHandlerAdapter? Handler) +{ + public PairUniqueIdentifier Ident => DisplayEntry.Ident; + public IReadOnlyList Groups => DisplayEntry.Groups; +} diff --git a/LightlessSync/UI/Models/PairUiSnapshot.cs b/LightlessSync/UI/Models/PairUiSnapshot.cs new file mode 100644 index 0000000..c9226b0 --- /dev/null +++ b/LightlessSync/UI/Models/PairUiSnapshot.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using LightlessSync.API.Dto.Group; +using LightlessSync.PlayerData.Pairs; + +namespace LightlessSync.UI.Models; + +public sealed record PairUiSnapshot( + IReadOnlyDictionary PairsByUid, + IReadOnlyList DirectPairs, + IReadOnlyDictionary> GroupPairs, + IReadOnlyDictionary> PairsWithGroups, + IReadOnlyDictionary GroupsByGid, + IReadOnlyCollection Groups) +{ + public static PairUiSnapshot Empty { get; } = new( + new ReadOnlyDictionary(new Dictionary()), + Array.Empty(), + new ReadOnlyDictionary>(new Dictionary>()), + new ReadOnlyDictionary>(new Dictionary>()), + new ReadOnlyDictionary(new Dictionary()), + Array.Empty()); +} diff --git a/LightlessSync/UI/Models/VisiblePairSortMode.cs b/LightlessSync/UI/Models/VisiblePairSortMode.cs new file mode 100644 index 0000000..fcb1d65 --- /dev/null +++ b/LightlessSync/UI/Models/VisiblePairSortMode.cs @@ -0,0 +1,11 @@ +namespace LightlessSync.UI.Models; + +public enum VisiblePairSortMode +{ + Default = 0, + Alphabetical = 1, + VramUsage = 2, + EffectiveVramUsage = 3, + TriangleCount = 4, + PreferredDirectPairs = 5, +} diff --git a/LightlessSync/UI/PopoutProfileUi.cs b/LightlessSync/UI/PopoutProfileUi.cs index 1737214..baa41a2 100644 --- a/LightlessSync/UI/PopoutProfileUi.cs +++ b/LightlessSync/UI/PopoutProfileUi.cs @@ -4,10 +4,11 @@ using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using LightlessSync.API.Data.Extensions; using LightlessSync.LightlessConfiguration; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; +using LightlessSync.UI.Services; +using LightlessSync.PlayerData.Pairs; using Microsoft.Extensions.Logging; using System.Numerics; @@ -16,7 +17,7 @@ namespace LightlessSync.UI; public class PopoutProfileUi : WindowMediatorSubscriberBase { private readonly LightlessProfileManager _lightlessProfileManager; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly ServerConfigurationManager _serverManager; private readonly UiSharedService _uiSharedService; private Vector2 _lastMainPos = Vector2.Zero; @@ -29,12 +30,12 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase public PopoutProfileUi(ILogger logger, LightlessMediator mediator, UiSharedService uiBuilder, ServerConfigurationManager serverManager, LightlessConfigService lightlessConfigService, - LightlessProfileManager lightlessProfileManager, PairManager pairManager, PerformanceCollectorService performanceCollectorService) : base(logger, mediator, "###LightlessSyncPopoutProfileUI", performanceCollectorService) + LightlessProfileManager lightlessProfileManager, PairUiService pairUiService, PerformanceCollectorService performanceCollectorService) : base(logger, mediator, "###LightlessSyncPopoutProfileUI", performanceCollectorService) { _uiSharedService = uiBuilder; _serverManager = serverManager; _lightlessProfileManager = lightlessProfileManager; - _pairManager = pairManager; + _pairUiService = pairUiService; Flags = ImGuiWindowFlags.NoDecoration; Mediator.Subscribe(this, (msg) => @@ -143,13 +144,17 @@ public class PopoutProfileUi : WindowMediatorSubscriberBase UiSharedService.ColorText("They: paused", UIColors.Get("LightlessYellow")); } } + var snapshot = _pairUiService.GetSnapshot(); + if (_pair.UserPair.Groups.Any()) { ImGui.TextUnformatted("Paired through Syncshells:"); foreach (var group in _pair.UserPair.Groups) { var groupNote = _serverManager.GetNoteForGid(group); - var groupName = _pairManager.GroupPairs.First(f => string.Equals(f.Key.GID, group, StringComparison.Ordinal)).Key.GroupAliasOrGID; + var groupName = snapshot.GroupsByGid.TryGetValue(group, out var groupInfo) + ? groupInfo.GroupAliasOrGID + : group; var groupString = string.IsNullOrEmpty(groupNote) ? groupName : $"{groupNote} ({groupName})"; ImGui.TextUnformatted("- " + groupString); } diff --git a/LightlessSync/UI/ProfileEditorLayoutCoordinator.cs b/LightlessSync/UI/ProfileEditorLayoutCoordinator.cs new file mode 100644 index 0000000..9a980fe --- /dev/null +++ b/LightlessSync/UI/ProfileEditorLayoutCoordinator.cs @@ -0,0 +1,84 @@ +using System; +using System.Numerics; +using System.Threading; + +namespace LightlessSync.UI; + +internal static class ProfileEditorLayoutCoordinator +{ + private static readonly Lock Gate = new(); + private static string? _activeUid; + private static Vector2? _anchor; + + private const float ProfileWidth = 840f; + private const float ProfileHeight = 525f; + private const float EditorWidth = 380f; + private const float Spacing = 0f; + private static readonly Vector2 DefaultOffset = new(50f, 70f); + + public static void Enable(string uid) + { + using var _ = Gate.EnterScope(); + if (!string.Equals(_activeUid, uid, StringComparison.Ordinal)) + _anchor = null; + _activeUid = uid; + } + + public static void Disable(string uid) + { + using var _ = Gate.EnterScope(); + if (string.Equals(_activeUid, uid, StringComparison.Ordinal)) + { + _activeUid = null; + _anchor = null; + } + } + + public static bool IsActive(string uid) + { + using var _ = Gate.EnterScope(); + return string.Equals(_activeUid, uid, StringComparison.Ordinal); + } + + public static Vector2 GetProfileSize(float scale) => new(ProfileWidth * scale, ProfileHeight * scale); + public static Vector2 GetEditorSize(float scale) => new(EditorWidth * scale, ProfileHeight * scale); + + public static Vector2 GetEditorOffset(float scale) => new((ProfileWidth + Spacing) * scale, 0f); + + public static Vector2 EnsureAnchor(Vector2 viewportOrigin, float scale) + { + using var _ = Gate.EnterScope(); + if (_anchor is null) + _anchor = viewportOrigin + DefaultOffset * scale; + return _anchor.Value; + } + + public static void UpdateAnchorFromProfile(Vector2 profilePosition) + { + using var _ = Gate.EnterScope(); + _anchor = profilePosition; + } + + public static void UpdateAnchorFromEditor(Vector2 editorPosition, float scale) + { + using var _ = Gate.EnterScope(); + _anchor = editorPosition - GetEditorOffset(scale); + } + + public static Vector2 GetProfilePosition(float scale) + { + using var _ = Gate.EnterScope(); + return _anchor ?? Vector2.Zero; + } + + public static Vector2 GetEditorPosition(float scale) + { + using var _ = Gate.EnterScope(); + return (_anchor ?? Vector2.Zero) + GetEditorOffset(scale); + } + + public static bool NearlyEquals(Vector2 current, Vector2 target, float epsilon = 0.5f) + { + return MathF.Abs(current.X - target.X) <= epsilon && MathF.Abs(current.Y - target.Y) <= epsilon; + } +} diff --git a/LightlessSync/UI/ProfileTags.cs b/LightlessSync/UI/ProfileTags.cs index 9fe4d6c..885eb7a 100644 --- a/LightlessSync/UI/ProfileTags.cs +++ b/LightlessSync/UI/ProfileTags.cs @@ -4,9 +4,30 @@ { SFW = 0, NSFW = 1, + RP = 2, ERP = 3, - Venues = 4, - Gpose = 5 + No_RP = 4, + No_ERP = 5, + + Venues = 6, + Gpose = 7, + + Limsa = 8, + Gridania = 9, + Ul_dah = 10, + + WUT = 11, + + PVP = 1001, + Ultimate = 1002, + Raids = 1003, + Roulette = 1004, + Crafting = 1005, + Casual = 1006, + Hardcore = 1007, + Glamour = 1008, + Mentor = 1009, + } } \ No newline at end of file diff --git a/LightlessSync/UI/Services/PairUiService.cs b/LightlessSync/UI/Services/PairUiService.cs new file mode 100644 index 0000000..5d38aec --- /dev/null +++ b/LightlessSync/UI/Services/PairUiService.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using LightlessSync.API.Dto.Group; +using LightlessSync.PlayerData.Factories; +using LightlessSync.PlayerData.Pairs; +using LightlessSync.Services.Mediator; +using LightlessSync.UI.Models; +using Microsoft.Extensions.Logging; + +namespace LightlessSync.UI.Services; + +public sealed class PairUiService : DisposableMediatorSubscriberBase +{ + private readonly PairLedger _pairLedger; + private readonly PairFactory _pairFactory; + private readonly PairManager _pairManager; + + private readonly object _snapshotGate = new(); + private PairUiSnapshot _snapshot = PairUiSnapshot.Empty; + private Pair? _lastAddedPair; + private bool _needsRefresh = true; + + public PairUiService( + ILogger logger, + LightlessMediator mediator, + PairLedger pairLedger, + PairFactory pairFactory, + PairManager pairManager) : base(logger, mediator) + { + _pairLedger = pairLedger; + _pairFactory = pairFactory; + _pairManager = pairManager; + + Mediator.Subscribe(this, _ => MarkDirty()); + Mediator.Subscribe(this, _ => MarkDirty()); + Mediator.Subscribe(this, _ => MarkDirty()); + + EnsureSnapshot(); + } + + public PairUiSnapshot GetSnapshot() + { + EnsureSnapshot(); + lock (_snapshotGate) + { + return _snapshot; + } + } + + public Pair? GetLastAddedPair() + { + EnsureSnapshot(); + lock (_snapshotGate) + { + return _lastAddedPair; + } + } + + public void ClearLastAddedPair() + { + _pairManager.ClearLastAddedUser(); + lock (_snapshotGate) + { + _lastAddedPair = null; + } + } + + private void MarkDirty() + { + lock (_snapshotGate) + { + _needsRefresh = true; + } + } + + private void EnsureSnapshot() + { + bool shouldBuild; + lock (_snapshotGate) + { + shouldBuild = _needsRefresh; + if (shouldBuild) + { + _needsRefresh = false; + } + } + + if (!shouldBuild) + { + return; + } + + PairUiSnapshot snapshot; + Pair? lastAddedPair; + try + { + (snapshot, lastAddedPair) = BuildSnapshot(); + } + catch + { + lock (_snapshotGate) + { + _needsRefresh = true; + } + + throw; + } + + lock (_snapshotGate) + { + _snapshot = snapshot; + _lastAddedPair = lastAddedPair; + } + + Mediator.Publish(new PairUiUpdatedMessage(snapshot)); + } + + private (PairUiSnapshot Snapshot, Pair? LastAddedPair) BuildSnapshot() + { + var entries = _pairLedger.GetAllEntries(); + var pairByUid = new Dictionary(StringComparer.Ordinal); + + var directPairsList = new List(); + var groupPairsTemp = new Dictionary>(); + var pairsWithGroupsTemp = new Dictionary>(); + + foreach (var entry in entries) + { + var pair = _pairFactory.Create(entry); + if (pair is null) + { + continue; + } + + pairByUid[entry.Ident.UserId] = pair; + + if (entry.IsDirectlyPaired) + { + directPairsList.Add(pair); + } + + var uniqueGroups = new HashSet(StringComparer.Ordinal); + var groupList = new List(); + foreach (var group in entry.Groups) + { + if (!uniqueGroups.Add(group.Group.GID)) + { + continue; + } + + if (!groupPairsTemp.TryGetValue(group, out var members)) + { + members = new List(); + groupPairsTemp[group] = members; + } + + members.Add(pair); + groupList.Add(group); + } + + pairsWithGroupsTemp[pair] = groupList; + } + + var allGroupsList = _pairLedger.GetAllSyncshells() + .Values + .Select(s => s.GroupFullInfo) + .ToList(); + + foreach (var group in allGroupsList) + { + if (!groupPairsTemp.ContainsKey(group)) + { + groupPairsTemp[group] = new List(); + } + } + + var directPairs = new ReadOnlyCollection(directPairsList); + + var groupPairsFinal = new Dictionary>(); + foreach (var (group, members) in groupPairsTemp) + { + groupPairsFinal[group] = new ReadOnlyCollection(members); + } + + var pairsWithGroupsFinal = new Dictionary>(); + foreach (var (pair, groups) in pairsWithGroupsTemp) + { + pairsWithGroupsFinal[pair] = new ReadOnlyCollection(groups); + } + + var groupsReadOnly = new ReadOnlyCollection(allGroupsList); + var pairsByUidReadOnly = new ReadOnlyDictionary(pairByUid); + var groupsByGidReadOnly = new ReadOnlyDictionary(allGroupsList.ToDictionary(g => g.Group.GID, g => g, StringComparer.Ordinal)); + + Pair? lastAddedPair = null; + var lastAdded = _pairManager.GetLastAddedUser(); + if (lastAdded is not null) + { + if (!pairByUid.TryGetValue(lastAdded.User.UID, out lastAddedPair)) + { + var groups = lastAdded.Groups.Keys + .Select(gid => + { + var result = _pairManager.GetGroup(gid); + return result.Success ? result.Value.GroupFullInfo : null; + }) + .Where(g => g is not null) + .Cast() + .ToList(); + + var entry = new PairDisplayEntry(new PairUniqueIdentifier(lastAdded.User.UID), lastAdded, groups, null); + lastAddedPair = _pairFactory.Create(entry); + } + } + + var snapshot = new PairUiSnapshot( + pairsByUidReadOnly, + directPairs, + new ReadOnlyDictionary>(groupPairsFinal), + new ReadOnlyDictionary>(pairsWithGroupsFinal), + groupsByGidReadOnly, + groupsReadOnly); + + return (snapshot, lastAddedPair); + } +} diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index 7cdeb38..cda8ac3 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -1,5 +1,6 @@ using Dalamud.Bindings.ImGui; using Dalamud.Game.Text; +using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; @@ -16,8 +17,10 @@ using LightlessSync.LightlessConfiguration.Models; using LightlessSync.PlayerData.Handlers; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; +using LightlessSync.Services.ActorTracking; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; +using LightlessSync.UI.Services; using LightlessSync.UI.Style; using LightlessSync.Utils; using LightlessSync.UtilsEnum.Enum; @@ -25,10 +28,12 @@ using LightlessSync.WebAPI; using LightlessSync.WebAPI.Files; using LightlessSync.WebAPI.Files.Models; using LightlessSync.WebAPI.SignalR.Utils; +using DalamudObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; using Microsoft.AspNetCore.Http.Connections; using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -37,6 +42,9 @@ using System.Net.Http.Json; using System.Numerics; using System.Text; using System.Text.Json; +using FFXIVClientStructs.FFXIV.Client.Game.Object; +using FfxivCharacter = FFXIVClientStructs.FFXIV.Client.Game.Character.Character; +using FfxivCharacterBase = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.CharacterBase; namespace LightlessSync.UI; @@ -54,7 +62,8 @@ public class SettingsUi : WindowMediatorSubscriberBase private readonly FileUploadManager _fileTransferManager; private readonly FileTransferOrchestrator _fileTransferOrchestrator; private readonly IpcManager _ipcManager; - private readonly PairManager _pairManager; + private readonly ActorObjectService _actorObjectService; + private readonly PairUiService _pairUiService; private readonly PerformanceCollectorService _performanceCollector; private readonly PlayerPerformanceConfigService _playerPerformanceConfigService; private readonly PairProcessingLimiter _pairProcessingLimiter; @@ -94,7 +103,7 @@ public class SettingsUi : WindowMediatorSubscriberBase public SettingsUi(ILogger logger, UiSharedService uiShared, LightlessConfigService configService, UiThemeConfigService themeConfigService, - PairManager pairManager, + PairUiService pairUiService, ServerConfigurationManager serverConfigurationManager, PlayerPerformanceConfigService playerPerformanceConfigService, PairProcessingLimiter pairProcessingLimiter, @@ -106,12 +115,13 @@ public class SettingsUi : WindowMediatorSubscriberBase IpcManager ipcManager, CacheMonitor cacheMonitor, DalamudUtilService dalamudUtilService, HttpClient httpClient, NameplateService nameplateService, - NameplateHandler nameplateHandler) : base(logger, mediator, "Lightless Sync Settings", + NameplateHandler nameplateHandler, + ActorObjectService actorObjectService) : base(logger, mediator, "Lightless Sync Settings", performanceCollector) { _configService = configService; _themeConfigService = themeConfigService; - _pairManager = pairManager; + _pairUiService = pairUiService; _serverConfigurationManager = serverConfigurationManager; _playerPerformanceConfigService = playerPerformanceConfigService; _pairProcessingLimiter = pairProcessingLimiter; @@ -128,13 +138,15 @@ public class SettingsUi : WindowMediatorSubscriberBase _uiShared = uiShared; _nameplateService = nameplateService; _nameplateHandler = nameplateHandler; + _actorObjectService = actorObjectService; AllowClickthrough = false; AllowPinning = true; _validationProgress = new Progress<(int, int, FileCacheEntity)>(v => _currentProgress = v); SizeConstraints = new WindowSizeConstraints() { - MinimumSize = new Vector2(800, 400), MaximumSize = new Vector2(800, 2000), + MinimumSize = new Vector2(850f, 400f), + MaximumSize = new Vector2(850f, 2000f), }; TitleBarButtons = new() @@ -449,6 +461,74 @@ public class SettingsUi : WindowMediatorSubscriberBase } } + private void DrawTextureDownscaleCounters() + { + HashSet trackedPairs = new(); + + var snapshot = _pairUiService.GetSnapshot(); + + foreach (var pair in snapshot.DirectPairs) + { + trackedPairs.Add(pair); + } + + foreach (var group in snapshot.GroupPairs.Values) + { + foreach (var pair in group) + { + trackedPairs.Add(pair); + } + } + + long totalOriginalBytes = 0; + long totalEffectiveBytes = 0; + var hasData = false; + + foreach (var pair in trackedPairs) + { + if (!pair.IsVisible) + continue; + + var original = pair.LastAppliedApproximateVRAMBytes; + var effective = pair.LastAppliedApproximateEffectiveVRAMBytes; + + if (original >= 0) + { + hasData = true; + totalOriginalBytes += original; + } + + if (effective >= 0) + { + hasData = true; + totalEffectiveBytes += effective; + } + } + + if (!hasData) + { + ImGui.TextDisabled("VRAM usage has not been calculated yet."); + return; + } + + var savedBytes = Math.Max(0L, totalOriginalBytes - totalEffectiveBytes); + var originalText = UiSharedService.ByteToString(totalOriginalBytes, addSuffix: true); + var effectiveText = UiSharedService.ByteToString(totalEffectiveBytes, addSuffix: true); + var savedText = UiSharedService.ByteToString(savedBytes, addSuffix: true); + + ImGui.TextUnformatted($"Total VRAM usage (original): {originalText}"); + ImGui.TextUnformatted($"Total VRAM usage (effective): {effectiveText}"); + + if (savedBytes > 0) + { + UiSharedService.ColorText($"VRAM saved by downscaling: {savedText}", UIColors.Get("LightlessGreen")); + } + else + { + ImGui.TextUnformatted($"VRAM saved by downscaling: {savedText}"); + } + } + private void DrawThemeVectorRow(MainStyle.StyleVector2Option option) { ImGui.TableNextRow(); @@ -1383,6 +1463,22 @@ public class SettingsUi : WindowMediatorSubscriberBase _logger.LogWarning(ex, $"Could not delete file {file} because it is in use."); } } + + foreach (var directory in Directory.GetDirectories(_configService.Current.CacheFolder)) + { + try + { + Directory.Delete(directory, recursive: true); + } + catch (IOException ex) + { + _logger.LogWarning(ex, "Could not delete directory {Directory} because it is in use.", directory); + } + catch (UnauthorizedAccessException ex) + { + _logger.LogWarning(ex, "Could not delete directory {Directory} due to access restrictions.", directory); + } + } }); } @@ -1422,8 +1518,9 @@ public class SettingsUi : WindowMediatorSubscriberBase { if (_uiShared.IconTextButton(FontAwesomeIcon.StickyNote, "Export all your user notes to clipboard")) { - ImGui.SetClipboardText(UiSharedService.GetNotes(_pairManager.DirectPairs - .UnionBy(_pairManager.GroupPairs.SelectMany(p => p.Value), p => p.UserData, + var snapshot = _pairUiService.GetSnapshot(); + ImGui.SetClipboardText(UiSharedService.GetNotes(snapshot.DirectPairs + .UnionBy(snapshot.GroupPairs.SelectMany(p => p.Value), p => p.UserData, UserDataComparer.Instance).ToList())); } @@ -2388,6 +2485,22 @@ public class SettingsUi : WindowMediatorSubscriberBase _uiShared.DrawHelpText( "Will show a performance indicator when players exceed defined thresholds in Lightless UI." + Environment.NewLine + "Will use warning thresholds."); + + using (ImRaii.Disabled(!showPerformanceIndicator)) + { + using var indent = ImRaii.PushIndent(); + bool showCompactStats = _playerPerformanceConfigService.Current.ShowPerformanceUsageNextToName; + if (ImGui.Checkbox("Show performance stats next to alias", ref showCompactStats)) + { + _playerPerformanceConfigService.Current.ShowPerformanceUsageNextToName = showCompactStats; + _playerPerformanceConfigService.Save(); + } + + _uiShared.DrawHelpText( + "Adds a text with approx. VRAM usage and triangle count to the right of pairs alias." + + Environment.NewLine + "Requires performance indicator to be enabled."); + } + bool warnOnExceedingThresholds = _playerPerformanceConfigService.Current.WarnOnExceedingThresholds; if (ImGui.Checkbox("Warn on loading in players exceeding performance thresholds", ref warnOnExceedingThresholds)) @@ -2552,6 +2665,102 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.TreePop(); } + ImGui.Separator(); + + if (_uiShared.MediumTreeNode("Texture Optimization", UIColors.Get("LightlessYellow"))) + { + _uiShared.MediumText("Warning", UIColors.Get("DimRed")); + _uiShared.DrawNoteLine("! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("Texture compression and downscaling is potentially a "), + new SeStringUtils.RichTextEntry("destructive", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" process and may cause broken or incorrect character appearances.")); + + _uiShared.DrawNoteLine("! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("This feature is encouraged to help "), + new SeStringUtils.RichTextEntry("lower-end systems with limited VRAM", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(" and for use in "), + new SeStringUtils.RichTextEntry("performance-critical scenarios", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiShared.DrawNoteLine("! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("Runtime downscaling "), + new SeStringUtils.RichTextEntry("MAY", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" cause higher load on the system when processing downloads.")); + + _uiShared.DrawNoteLine("!!! ", UIColors.Get("DimRed"), + new SeStringUtils.RichTextEntry("When enabled, we cannot provide support for appearance issues caused by this setting!", UIColors.Get("DimRed"), true)); + + var textureConfig = _playerPerformanceConfigService.Current; + var trimNonIndex = textureConfig.EnableNonIndexTextureMipTrim; + if (ImGui.Checkbox("Trim mip levels for textures", ref trimNonIndex)) + { + textureConfig.EnableNonIndexTextureMipTrim = trimNonIndex; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("When enabled, Lightless will remove high-resolution mip levels from textures (not index) that exceed the size limit and are not compressed with any kind compression."); + + var downscaleIndex = textureConfig.EnableIndexTextureDownscale; + if (ImGui.Checkbox("Downscale index textures above limit", ref downscaleIndex)) + { + textureConfig.EnableIndexTextureDownscale = downscaleIndex; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("Controls whether Lightless reduces index textures that exceed the size limit."); + + var dimensionOptions = new[] { 512, 1024, 2048, 4096 }; + var optionLabels = dimensionOptions.Select(static value => value.ToString()).ToArray(); + var currentDimension = textureConfig.TextureDownscaleMaxDimension; + var selectedIndex = Array.IndexOf(dimensionOptions, currentDimension); + if (selectedIndex < 0) + { + selectedIndex = Array.IndexOf(dimensionOptions, 2048); + } + + ImGui.SetNextItemWidth(140 * ImGuiHelpers.GlobalScale); + if (ImGui.Combo("Maximum texture dimension", ref selectedIndex, optionLabels, optionLabels.Length)) + { + textureConfig.TextureDownscaleMaxDimension = dimensionOptions[selectedIndex]; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText($"Textures above this size will be reduced until their largest dimension is at or below the limit. Block-compressed textures are skipped when \"Only downscale uncompressed\" is enabled.{UiSharedService.TooltipSeparator}Default: 2048"); + + var keepOriginalTextures = textureConfig.KeepOriginalTextureFiles; + if (ImGui.Checkbox("Keep original texture files", ref keepOriginalTextures)) + { + textureConfig.KeepOriginalTextureFiles = keepOriginalTextures; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("When disabled, Lightless removes the original texture after a downscaled copy is created."); + ImGui.SameLine(); + _uiShared.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), new SeStringUtils.RichTextEntry("If disabled, saved + effective VRAM usage information will not work.", UIColors.Get("LightlessYellow"))); + + if (!textureConfig.EnableNonIndexTextureMipTrim && !textureConfig.EnableIndexTextureDownscale) + { + UiSharedService.ColorTextWrapped("Both trimming and downscale are disabled. Lightless will keep original textures regardless of size.", UIColors.Get("DimRed")); + } + + ImGui.Dummy(new Vector2(5)); + + _uiShared.ColoredSeparator(UIColors.Get("DimRed"), 3f); + var onlyUncompressed = textureConfig.OnlyDownscaleUncompressedTextures; + if (ImGui.Checkbox("Only downscale uncompressed textures", ref onlyUncompressed)) + { + textureConfig.OnlyDownscaleUncompressedTextures = onlyUncompressed; + _playerPerformanceConfigService.Save(); + } + _uiShared.DrawHelpText("If disabled, compressed textures will be targeted for downscaling too."); + _uiShared.ColoredSeparator(UIColors.Get("DimRed"), 3f); + + ImGui.Dummy(new Vector2(5)); + + DrawTextureDownscaleCounters(); + + ImGui.Dummy(new Vector2(5)); + + _uiShared.ColoredSeparator(UIColors.Get("LightlessYellow"), 1.5f); + ImGui.TreePop(); + } + ImGui.Separator(); ImGui.Dummy(new Vector2(10)); @@ -3511,7 +3720,7 @@ public class SettingsUi : WindowMediatorSubscriberBase // Lightless notification locations var lightlessLocations = GetLightlessNotificationLocations(); var downloadLocations = GetDownloadNotificationLocations(); - + if (ImGui.BeginTable("##NotificationLocationTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit)) { ImGui.TableSetupColumn("Notification Type", ImGuiTableColumnFlags.WidthFixed, 200f * ImGuiHelpers.GlobalScale); @@ -3674,7 +3883,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.EndTable(); } - + ImGuiHelpers.ScaledDummy(5); if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Clear All Notifications")) { @@ -3792,7 +4001,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.Spacing(); ImGui.TextUnformatted("Size & Layout"); - + float notifWidth = _configService.Current.NotificationWidth; if (ImGui.SliderFloat("Notification Width", ref notifWidth, 250f, 600f, "%.0f")) { @@ -3825,7 +4034,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.Spacing(); ImGui.TextUnformatted("Position"); - + var currentCorner = _configService.Current.NotificationCorner; if (ImGui.BeginCombo("Notification Position", GetNotificationCornerLabel(currentCorner))) { @@ -3843,7 +4052,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.EndCombo(); } _uiShared.DrawHelpText("Choose which corner of the screen notifications appear in."); - + int offsetY = _configService.Current.NotificationOffsetY; if (ImGui.SliderInt("Vertical Offset", ref offsetY, -2500, 2500)) { @@ -4136,7 +4345,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.Separator(); // Location descriptions removed - information is now inline with each setting - + } } @@ -4256,7 +4465,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.TableSetColumnIndex(2); var availableWidth = ImGui.GetContentRegionAvail().X; var buttonWidth = (availableWidth - ImGui.GetStyle().ItemSpacing.X * 2) / 3; - + // Play button using var playId = ImRaii.PushId($"Play_{typeIndex}"); using (ImRaii.Disabled(isDisabled)) @@ -4277,7 +4486,7 @@ public class SettingsUi : WindowMediatorSubscriberBase } } UiSharedService.AttachToolTip("Test this sound"); - + // Disable toggle button ImGui.SameLine(); using var disableId = ImRaii.PushId($"Disable_{typeIndex}"); @@ -4285,11 +4494,11 @@ public class SettingsUi : WindowMediatorSubscriberBase { var icon = isDisabled ? FontAwesomeIcon.VolumeOff : FontAwesomeIcon.VolumeUp; var color = isDisabled ? UIColors.Get("DimRed") : UIColors.Get("LightlessGreen"); - + ImGui.PushStyleColor(ImGuiCol.Button, color); ImGui.PushStyleColor(ImGuiCol.ButtonHovered, color * new Vector4(1.2f, 1.2f, 1.2f, 1f)); ImGui.PushStyleColor(ImGuiCol.ButtonActive, color * new Vector4(0.8f, 0.8f, 0.8f, 1f)); - + if (ImGui.Button(icon.ToIconString(), new Vector2(buttonWidth, 0))) { bool newDisabled = !isDisabled; @@ -4303,16 +4512,16 @@ public class SettingsUi : WindowMediatorSubscriberBase } _configService.Save(); } - + ImGui.PopStyleColor(3); } UiSharedService.AttachToolTip(isDisabled ? "Sound is disabled - click to enable" : "Sound is enabled - click to disable"); - + // Reset button ImGui.SameLine(); using var resetId = ImRaii.PushId($"Reset_{typeIndex}"); bool isDefault = currentSoundId == defaultSoundId; - + using (ImRaii.Disabled(isDefault)) { using (ImRaii.PushFont(UiBuilder.IconFont)) @@ -4337,6 +4546,4 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.EndTable(); } } -} - - +} \ No newline at end of file diff --git a/LightlessSync/UI/StandaloneProfileUi.cs b/LightlessSync/UI/StandaloneProfileUi.cs index 6ef21d5..22e42aa 100644 --- a/LightlessSync/UI/StandaloneProfileUi.cs +++ b/LightlessSync/UI/StandaloneProfileUi.cs @@ -1,13 +1,21 @@ -using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Colors; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.ImGuiSeStringRenderer; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; +using LightlessSync.API.Data; using LightlessSync.API.Data.Extensions; +using LightlessSync.API.Dto.Group; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Services.ServerConfiguration; +using LightlessSync.UI.Services; +using LightlessSync.UI.Tags; +using LightlessSync.Utils; using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; using System.Numerics; namespace LightlessSync.UI; @@ -15,167 +23,1212 @@ namespace LightlessSync.UI; public class StandaloneProfileUi : WindowMediatorSubscriberBase { private readonly LightlessProfileManager _lightlessProfileManager; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly ServerConfigurationManager _serverManager; + private readonly ProfileTagService _profileTagService; private readonly UiSharedService _uiSharedService; - private bool _adjustedForScrollBars = false; + private readonly UserData? _userData; + private readonly GroupFullInfoDto? _groupInfo; + private readonly GroupData? _groupData; + private readonly bool _isGroupProfile; + private readonly bool _isLightfinderContext; + private readonly string? _lightfinderCid; private byte[] _lastProfilePicture = []; private byte[] _lastSupporterPicture = []; + private byte[] _lastBannerPicture = []; private IDalamudTextureWrap? _supporterTextureWrap; private IDalamudTextureWrap? _textureWrap; + private IDalamudTextureWrap? _bannerTextureWrap; + private bool _bannerTextureLoaded; + private Vector4 _tagBackgroundColor = new(0.18f, 0.18f, 0.18f, 0.95f); + private Vector4 _tagBorderColor = new(0.35f, 0.35f, 0.35f, 0.4f); + private readonly List _seResolvedSegments = new(); + private const float MaxHeightMultiplier = 2.5f; + private const float DescriptionMaxVisibleLines = 12f; + private const string UserDescriptionPlaceholder = "-- User has no description set --"; + private const string GroupDescriptionPlaceholder = "-- Syncshell has no description set --"; + private float _lastComputedWindowHeight = -1f; - public StandaloneProfileUi(ILogger logger, LightlessMediator mediator, UiSharedService uiBuilder, - ServerConfigurationManager serverManager, LightlessProfileManager lightlessProfileManager, PairManager pairManager, Pair pair, + public StandaloneProfileUi( + ILogger logger, + LightlessMediator mediator, + UiSharedService uiBuilder, + ServerConfigurationManager serverManager, + ProfileTagService profileTagService, + LightlessProfileManager lightlessProfileManager, + PairUiService pairUiService, + Pair? pair, + UserData? userData, + GroupFullInfoDto? groupInfo, + bool isLightfinderContext, + string? lightfinderCid, PerformanceCollectorService performanceCollector) - : base(logger, mediator, "Lightless Profile of " + pair.UserData.AliasOrUID + "##LightlessSyncStandaloneProfileUI" + pair.UserData.AliasOrUID, performanceCollector) + : base(logger, mediator, BuildWindowTitle(userData, groupInfo, isLightfinderContext), performanceCollector) { _uiSharedService = uiBuilder; _serverManager = serverManager; + _profileTagService = profileTagService; _lightlessProfileManager = lightlessProfileManager; Pair = pair; - _pairManager = pairManager; - Flags = ImGuiWindowFlags.NoResize | ImGuiWindowFlags.AlwaysAutoResize; + _pairUiService = pairUiService; + _userData = userData; + _groupInfo = groupInfo; + _groupData = groupInfo?.Group; + _isGroupProfile = groupInfo is not null; + _isLightfinderContext = isLightfinderContext; + _lightfinderCid = lightfinderCid; - var spacing = ImGui.GetStyle().ItemSpacing; + Flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoResize; - Size = new(512 + spacing.X * 3 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 512); + var fixedSize = new Vector2(840f, 525f) * ImGuiHelpers.GlobalScale; + Size = fixedSize; + SizeCondition = ImGuiCond.Always; + SizeConstraints = new() + { + MinimumSize = fixedSize, + MaximumSize = new Vector2(fixedSize.X, fixedSize.Y * MaxHeightMultiplier) + }; IsOpen = true; } - public Pair Pair { get; init; } + public Pair? Pair { get; } + public bool IsGroupProfile => _isGroupProfile; + public GroupData? ProfileGroupData => _groupData; + public bool IsLightfinderContext => _isLightfinderContext; + public string? LightfinderCid => _lightfinderCid; + public UserData ProfileUserData => _userData ?? throw new InvalidOperationException("ProfileUserData is only available for user profiles."); + + public void SetTagColorTheme(Vector4? background, Vector4? border) + { + if (background.HasValue) + _tagBackgroundColor = background.Value; + if (border.HasValue) + _tagBorderColor = border.Value; + } + + private static Vector4 ResolveThemeColor(string colorName, Vector4 fallback) + { + try + { + return UIColors.Get(colorName); + } + catch (ArgumentException) + { + // fallback when the color key is not registered + } + + return fallback; + } + + private static string BuildWindowTitle(UserData? userData, GroupFullInfoDto? groupInfo, bool isLightfinderContext) + { + if (groupInfo is not null) + { + var alias = groupInfo.GroupAliasOrGID; + return $"Syncshell Profile of {alias}##LightlessSyncStandaloneGroupProfileUI{groupInfo.Group.GID}"; + } + + if (userData is null) + return "Lightless Profile##LightlessSyncStandaloneProfileUI"; + + var name = userData.AliasOrUID; + var suffix = isLightfinderContext ? " (Lightfinder)" : string.Empty; + return $"Lightless Profile of {name}{suffix}##LightlessSyncStandaloneProfileUI{name}"; + } protected override void DrawInternal() { try { - var spacing = ImGui.GetStyle().ItemSpacing; - - var lightlessProfile = _lightlessProfileManager.GetLightlessUserProfile(Pair.UserData); - - if (_textureWrap == null || !lightlessProfile.ImageData.Value.SequenceEqual(_lastProfilePicture)) + if (_isGroupProfile) { - _textureWrap?.Dispose(); - _lastProfilePicture = lightlessProfile.ImageData.Value; - _textureWrap = _uiSharedService.LoadImage(_lastProfilePicture); + DrawGroupProfileWindow(); + return; } - if (_supporterTextureWrap == null || !lightlessProfile.SupporterImageData.Value.SequenceEqual(_lastSupporterPicture)) + if (_userData is null) + return; + + var userData = _userData; + var scale = ImGuiHelpers.GlobalScale; + var viewport = ImGui.GetMainViewport(); + var linked = !_isLightfinderContext + && Pair is null + && ProfileEditorLayoutCoordinator.IsActive(userData.UID); + var baseSize = ProfileEditorLayoutCoordinator.GetProfileSize(scale); + var baseWidth = baseSize.X; + var minHeight = baseSize.Y; + var maxAllowedHeight = minHeight * MaxHeightMultiplier; + var targetHeight = _lastComputedWindowHeight > 0f + ? Math.Clamp(_lastComputedWindowHeight, minHeight, maxAllowedHeight) + : minHeight; + var desiredSize = new Vector2(baseWidth, targetHeight); + Size = desiredSize; + if (linked) + { + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); + + var currentPos = ImGui.GetWindowPos(); + if (IsWindowBeingDragged()) + ProfileEditorLayoutCoordinator.UpdateAnchorFromProfile(currentPos); + + var desiredPos = ProfileEditorLayoutCoordinator.GetProfilePosition(scale); + if (!ProfileEditorLayoutCoordinator.NearlyEquals(currentPos, desiredPos)) + ImGui.SetWindowPos(desiredPos, ImGuiCond.Always); + + if (!ProfileEditorLayoutCoordinator.NearlyEquals(ImGui.GetWindowSize(), desiredSize)) + ImGui.SetWindowSize(desiredSize, ImGuiCond.Always); + } + else + { + var defaultPosition = viewport.WorkPos + (new Vector2(50f, 70f) * scale); + ImGui.SetWindowPos(defaultPosition, ImGuiCond.FirstUseEver); + ImGui.SetWindowSize(desiredSize, ImGuiCond.Always); + } + + var profile = _lightlessProfileManager.GetLightlessProfile(userData); + IReadOnlyList profileTags = profile.Tags.Count > 0 + ? _profileTagService.ResolveTags(profile.Tags) + : Array.Empty(); + + if (_textureWrap == null || !profile.ImageData.Value.SequenceEqual(_lastProfilePicture)) + { + _textureWrap?.Dispose(); + _textureWrap = null; + _lastProfilePicture = profile.ImageData.Value; + ResetBannerTexture(); + if (_lastProfilePicture.Length > 0) + { + _textureWrap = _uiSharedService.LoadImage(_lastProfilePicture); + } + } + + if (_supporterTextureWrap == null || !profile.SupporterImageData.Value.SequenceEqual(_lastSupporterPicture)) { _supporterTextureWrap?.Dispose(); _supporterTextureWrap = null; - if (!string.IsNullOrEmpty(lightlessProfile.Base64SupporterPicture)) + if (!string.IsNullOrEmpty(profile.Base64SupporterPicture)) { - _lastSupporterPicture = lightlessProfile.SupporterImageData.Value; - _supporterTextureWrap = _uiSharedService.LoadImage(_lastSupporterPicture); + _lastSupporterPicture = profile.SupporterImageData.Value; + if (_lastSupporterPicture.Length > 0) + { + _supporterTextureWrap = _uiSharedService.LoadImage(_lastSupporterPicture); + } } } + var bannerBytes = profile.BannerImageData.Value; + if (!_lastBannerPicture.SequenceEqual(bannerBytes)) + { + ResetBannerTexture(); + _lastBannerPicture = bannerBytes; + } + + string? noteText = null; + string statusLabel = _isLightfinderContext ? "Exploring" : "Offline"; + string? visiblePlayerName = null; + bool directPair = false; + bool youPaused = false; + bool theyPaused = false; + List syncshellLines = new(); + + if (!_isLightfinderContext && Pair != null) + { + var snapshot = _pairUiService.GetSnapshot(); + noteText = _serverManager.GetNoteForUid(Pair.UserData.UID); + statusLabel = Pair.IsVisible ? "Visible" : (Pair.IsOnline ? "Online" : "Offline"); + visiblePlayerName = Pair.IsVisible ? Pair.PlayerName : null; + + directPair = Pair.IsDirectlyPaired; + + var pairInfo = Pair.UserPair; + if (pairInfo != null) + { + if (directPair) + { + youPaused = pairInfo.OwnPermissions.IsPaused(); + theyPaused = pairInfo.OtherPermissions.IsPaused(); + } + + if (pairInfo.Groups.Any()) + { + foreach (var gid in pairInfo.Groups) + { + var groupLabel = snapshot.GroupsByGid.TryGetValue(gid, out var groupInfo) + ? groupInfo.GroupAliasOrGID + : gid; + var groupNote = _serverManager.GetNoteForGid(gid); + syncshellLines.Add(string.IsNullOrEmpty(groupNote) ? groupLabel : $"{groupNote} ({groupLabel})"); + } + } + } + } + + var presenceTokens = new List + { + new(statusLabel, string.Equals(statusLabel, "Offline", StringComparison.OrdinalIgnoreCase)) + }; + + if (!string.IsNullOrEmpty(visiblePlayerName)) + presenceTokens.Add(new PresenceToken(visiblePlayerName, false)); + + if (directPair) + { + presenceTokens.Add(new PresenceToken("Direct Pair", true)); + if (youPaused) + presenceTokens.Add(new PresenceToken("You paused syncing", true)); + if (theyPaused) + presenceTokens.Add(new PresenceToken("They paused syncing", true)); + } + + if (syncshellLines.Count > 0) + presenceTokens.Add(new PresenceToken($"Sharing Syncshells ({syncshellLines.Count})", false, syncshellLines, "Shared Syncshells")); + var drawList = ImGui.GetWindowDrawList(); - var rectMin = drawList.GetClipRectMin(); - var rectMax = drawList.GetClipRectMax(); - var headerSize = ImGui.GetCursorPosY() - ImGui.GetStyle().WindowPadding.Y; + var style = ImGui.GetStyle(); + var windowPos = ImGui.GetWindowPos(); + var windowSize = ImGui.GetWindowSize(); + var bannerHeight = 260f * scale; + var portraitSize = new Vector2(180f, 180f) * scale; + var portraitBorder = 1.5f * scale; + var portraitRounding = 1f * scale; + var portraitFrameSize = portraitSize + new Vector2(portraitBorder * 2f); + var portraitOverlap = portraitSize.Y * 0.35f; + var portraitOffsetX = 35f * scale; + var infoOffsetX = portraitOffsetX + portraitFrameSize.X + style.ItemSpacing.X * 2f; + var bannerTexture = GetBannerTexture(_lastBannerPicture) ?? _textureWrap ?? _supporterTextureWrap; - using (_uiSharedService.UidFont.Push()) - UiSharedService.ColorText(Pair.UserData.AliasOrUID, UIColors.Get("LightlessBlue")); + string defaultSubtitle = !_isLightfinderContext && Pair != null && !string.IsNullOrEmpty(Pair.UserData.Alias) + ? Pair.UserData.Alias! + : _isLightfinderContext ? "Lightfinder Session" : noteText ?? string.Empty; - ImGuiHelpers.ScaledDummy(new Vector2(spacing.Y, spacing.Y)); - var textPos = ImGui.GetCursorPosY() - headerSize; - ImGui.Separator(); - var pos = ImGui.GetCursorPos() with { Y = ImGui.GetCursorPosY() - headerSize }; - ImGuiHelpers.ScaledDummy(new Vector2(256, 256 + spacing.Y)); - var postDummy = ImGui.GetCursorPosY(); - ImGui.SameLine(); - var descriptionTextSize = ImGui.CalcTextSize(lightlessProfile.Description, wrapWidth: 256f); - var descriptionChildHeight = rectMax.Y - pos.Y - rectMin.Y - spacing.Y * 2; - if (descriptionTextSize.Y > descriptionChildHeight && !_adjustedForScrollBars) - { - Size = Size!.Value with { X = Size.Value.X + ImGui.GetStyle().ScrollbarSize }; - _adjustedForScrollBars = true; - } - else if (descriptionTextSize.Y < descriptionChildHeight && _adjustedForScrollBars) - { - Size = Size!.Value with { X = Size.Value.X - ImGui.GetStyle().ScrollbarSize }; - _adjustedForScrollBars = false; - } - var childFrame = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, descriptionChildHeight); - childFrame = childFrame with - { - X = childFrame.X + (_adjustedForScrollBars ? ImGui.GetStyle().ScrollbarSize : 0), - Y = childFrame.Y / ImGuiHelpers.GlobalScale - }; - if (ImGui.BeginChildFrame(1000, childFrame)) - { - using var _ = _uiSharedService.GameFont.Push(); - ImGui.TextWrapped(lightlessProfile.Description); - } - ImGui.EndChildFrame(); + bool hasVanityAlias = userData.HasVanity && !string.IsNullOrWhiteSpace(userData.Alias); + Vector4? vanityTextColor = null; + Vector4? vanityGlowColor = null; - ImGui.SetCursorPosY(postDummy); - var note = _serverManager.GetNoteForUid(Pair.UserData.UID); - if (!string.IsNullOrEmpty(note)) + if (hasVanityAlias) { - UiSharedService.ColorText(note, ImGuiColors.DalamudGrey); + if (!string.IsNullOrWhiteSpace(userData.TextColorHex)) + vanityTextColor = UIColors.HexToRgba(userData.TextColorHex); + + if (!string.IsNullOrWhiteSpace(userData.TextGlowColorHex)) + vanityGlowColor = UIColors.HexToRgba(userData.TextGlowColorHex); } - string status = Pair.IsVisible ? "Visible" : (Pair.IsOnline ? "Online" : "Offline"); - UiSharedService.ColorText(status, (Pair.IsVisible || Pair.IsOnline) ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudRed); - if (Pair.IsVisible) + + bool useVanityColors = vanityTextColor.HasValue || vanityGlowColor.HasValue; + string primaryHeaderText = hasVanityAlias ? userData.Alias! : userData.UID; + + List<(string Text, bool UseVanityColor, bool Disabled)> secondaryHeaderLines = new(); + if (hasVanityAlias) { - ImGui.SameLine(); - ImGui.TextUnformatted($"({Pair.PlayerName})"); - } - if (Pair.UserPair != null) - { - ImGui.TextUnformatted("Directly paired"); - if (Pair.UserPair.OwnPermissions.IsPaused()) + secondaryHeaderLines.Add((userData.UID, useVanityColors, false)); + + if (!string.IsNullOrEmpty(defaultSubtitle) + && !string.Equals(defaultSubtitle, userData.UID, StringComparison.OrdinalIgnoreCase) + && !string.Equals(defaultSubtitle, userData.Alias, StringComparison.OrdinalIgnoreCase)) { - ImGui.SameLine(); - UiSharedService.ColorText("You: paused", UIColors.Get("LightlessYellow")); - } - if (Pair.UserPair.OtherPermissions.IsPaused()) - { - ImGui.SameLine(); - UiSharedService.ColorText("They: paused", UIColors.Get("LightlessYellow")); + secondaryHeaderLines.Add((defaultSubtitle, false, true)); } } - - if (Pair.UserPair.Groups.Any()) + else if (!string.IsNullOrEmpty(defaultSubtitle) + && !string.Equals(defaultSubtitle, userData.UID, StringComparison.OrdinalIgnoreCase)) { - ImGui.TextUnformatted("Paired through Syncshells:"); - foreach (var group in Pair.UserPair.Groups) - { - var groupNote = _serverManager.GetNoteForGid(group); - var groupName = _pairManager.GroupPairs.First(f => string.Equals(f.Key.GID, group, StringComparison.Ordinal)).Key.GroupAliasOrGID; - var groupString = string.IsNullOrEmpty(groupNote) ? groupName : $"{groupNote} ({groupName})"; - ImGui.TextUnformatted("- " + groupString); - } + secondaryHeaderLines.Add((defaultSubtitle, false, true)); + } + + var bannerScrollOffset = new Vector2(ImGui.GetScrollX(), ImGui.GetScrollY()); + var bannerMin = windowPos - bannerScrollOffset; + var bannerMax = bannerMin + new Vector2(windowSize.X, bannerHeight); + + if (bannerTexture != null) + { + drawList.AddImage( + bannerTexture.Handle, + bannerMin, + bannerMax); + } + else + { + var headerBase = ImGui.ColorConvertU32ToFloat4(ImGui.GetColorU32(ImGuiCol.Header)); + var topColor = ResolveThemeColor("ProfileBodyGradientTop", Vector4.Lerp(headerBase, Vector4.One, 0.25f)); + topColor.W = 1f; + var bottomColor = ResolveThemeColor("ProfileBodyGradientBottom", Vector4.Lerp(headerBase, Vector4.Zero, 0.35f)); + bottomColor.W = 1f; + + drawList.AddRectFilledMultiColor( + bannerMin, + bannerMax, + ImGui.ColorConvertFloat4ToU32(topColor), + ImGui.ColorConvertFloat4ToU32(topColor), + ImGui.ColorConvertFloat4ToU32(bottomColor), + ImGui.ColorConvertFloat4ToU32(bottomColor)); } - var padding = ImGui.GetStyle().WindowPadding.X / 2; - bool tallerThanWide = _textureWrap.Height >= _textureWrap.Width; - var stretchFactor = tallerThanWide ? 256f * ImGuiHelpers.GlobalScale / _textureWrap.Height : 256f * ImGuiHelpers.GlobalScale / _textureWrap.Width; - var newWidth = _textureWrap.Width * stretchFactor; - var newHeight = _textureWrap.Height * stretchFactor; - var remainingWidth = (256f * ImGuiHelpers.GlobalScale - newWidth) / 2f; - var remainingHeight = (256f * ImGuiHelpers.GlobalScale - newHeight) / 2f; - drawList.AddImage(_textureWrap.Handle, new Vector2(rectMin.X + padding + remainingWidth, rectMin.Y + spacing.Y + pos.Y + remainingHeight), - new Vector2(rectMin.X + padding + remainingWidth + newWidth, rectMin.Y + spacing.Y + pos.Y + remainingHeight + newHeight)); if (_supporterTextureWrap != null) { - const float iconSize = 38; - drawList.AddImage(_supporterTextureWrap.Handle, - new Vector2(rectMax.X - iconSize - spacing.X, rectMin.Y + (textPos / 2) - (iconSize / 2)), - new Vector2(rectMax.X - spacing.X, rectMin.Y + iconSize + (textPos / 2) - (iconSize / 2))); + const float iconBaseSize = 40f; + var iconPadding = new Vector2(style.WindowPadding.X + 18f * scale, style.WindowPadding.Y + 18f * scale); + var textureWidth = MathF.Max(1f, _supporterTextureWrap.Width); + var textureHeight = MathF.Max(1f, _supporterTextureWrap.Height); + var textureMaxEdge = MathF.Max(textureWidth, textureHeight); + var iconScale = (iconBaseSize * scale) / textureMaxEdge; + var iconSize = new Vector2(textureWidth * iconScale, textureHeight * iconScale); + var iconMax = bannerMax - iconPadding; + var iconMin = iconMax - iconSize; + var backgroundPadding = 6f * scale; + var iconBackgroundMin = iconMin - new Vector2(backgroundPadding); + var iconBackgroundMax = iconMax + new Vector2(backgroundPadding); + var backgroundColor = new Vector4(0f, 0f, 0f, 0.65f); + var cornerRadius = MathF.Max(4f * scale, iconSize.Y * 0.25f); + + drawList.AddRectFilled(iconBackgroundMin, iconBackgroundMax, ImGui.GetColorU32(backgroundColor), cornerRadius); + drawList.AddImage(_supporterTextureWrap.Handle, iconMin, iconMax); } + + var contentStartY = MathF.Max(style.WindowPadding.Y, bannerHeight - portraitOverlap); + var topAreaStart = ImGui.GetCursorPos(); + + var portraitBackgroundPadding = 12f * scale; + var portraitAreaSize = portraitFrameSize + new Vector2(portraitBackgroundPadding * 2f); + var portraitAreaPos = new Vector2(style.WindowPadding.X + portraitOffsetX - portraitBackgroundPadding, contentStartY - portraitBackgroundPadding - 24f * scale); + + ImGui.SetCursorPos(portraitAreaPos); + var portraitAreaScreenPos = ImGui.GetCursorScreenPos(); + ImGui.Dummy(portraitAreaSize); + + var portraitAreaMin = portraitAreaScreenPos; + var portraitAreaMax = portraitAreaMin + portraitAreaSize; + var portraitFrameMin = portraitAreaMin + new Vector2(portraitBackgroundPadding); + var portraitFrameMax = portraitFrameMin + portraitFrameSize; + + var portraitAreaColor = style.Colors[(int)ImGuiCol.WindowBg]; + portraitAreaColor.W = MathF.Min(1f, portraitAreaColor.W + 0.2f); + drawList.AddRectFilled(portraitAreaMin, portraitAreaMax, ImGui.GetColorU32(portraitAreaColor), portraitRounding + portraitBorder + portraitBackgroundPadding); + + var portraitFrameBorder = style.Colors[(int)ImGuiCol.Border]; + + if (_textureWrap != null) + { + drawList.AddImageRounded( + _textureWrap.Handle, + portraitFrameMin + new Vector2(portraitBorder, portraitBorder), + portraitFrameMax - new Vector2(portraitBorder, portraitBorder), + Vector2.Zero, + Vector2.One, + 0xFFFFFFFF, + portraitRounding); + } + else + { + drawList.AddRect( + portraitFrameMin + new Vector2(portraitBorder, portraitBorder), + portraitFrameMax - new Vector2(portraitBorder, portraitBorder), + ImGui.GetColorU32(portraitFrameBorder), + portraitRounding); + } + + var portraitAreaLocalMin = portraitAreaMin - windowPos; + var portraitAreaLocalMax = portraitAreaMax - windowPos; + var portraitFrameLocalMin = portraitFrameMin - windowPos; + var portraitFrameLocalMax = portraitFrameMax - windowPos; + var portraitBlockBottom = windowPos.Y + portraitAreaLocalMax.Y; + + var infoStartY = MathF.Max(contentStartY, bannerHeight + style.WindowPadding.Y); + var aliasColumnX = infoOffsetX + 18f * scale; + ImGui.SetCursorPos(new Vector2(aliasColumnX, infoStartY)); + + ImGui.BeginGroup(); + using (_uiSharedService.UidFont.Push()) + { + if (useVanityColors) + { + var seString = SeStringUtils.BuildFormattedPlayerName(primaryHeaderText, vanityTextColor, vanityGlowColor); + SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont()); + } + else + { + ImGui.TextUnformatted(primaryHeaderText); + } + } + + foreach (var (text, useColor, disabled) in secondaryHeaderLines) + { + if (useColor && useVanityColors) + { + var seString = SeStringUtils.BuildFormattedPlayerName(text, vanityTextColor, vanityGlowColor); + SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont()); + } + else + { + if (disabled) + ImGui.TextDisabled(text); + else + ImGui.TextUnformatted(text); + } + } + ImGui.EndGroup(); + var namesEnd = ImGui.GetCursorPos(); + + var namesBlockBottom = windowPos.Y + namesEnd.Y; + var aliasGroupRectMin = ImGui.GetItemRectMin(); + var aliasGroupRectMax = ImGui.GetItemRectMax(); + var aliasGroupLocalMin = aliasGroupRectMin - windowPos; + var aliasGroupLocalMax = aliasGroupRectMax - windowPos; + + var tagsStartLocal = new Vector2(aliasGroupLocalMax.X + style.ItemSpacing.X + 25f * scale, aliasGroupLocalMin.Y + style.FramePadding.Y + 2f * scale); + ImGui.SetCursorPos(tagsStartLocal); + RenderProfileTags(profileTags, scale); + var tagsEndLocal = ImGui.GetCursorPos(); + var tagsBlockBottom = windowPos.Y + tagsEndLocal.Y; + var aliasBlockBottom = windowPos.Y + aliasGroupLocalMax.Y; + var aliasAndTagsBottomLocal = MathF.Max(aliasGroupLocalMax.Y, tagsEndLocal.Y); + var aliasAndTagsBlockBottom = MathF.Max(aliasBlockBottom, tagsBlockBottom); + + var descriptionPreSpacing = style.ItemSpacing.Y * 1.35f; + var descriptionStartLocal = new Vector2(aliasColumnX, aliasAndTagsBottomLocal + descriptionPreSpacing); + var horizontalInset = style.ItemSpacing.X * 0.5f; + var descriptionSeparatorSpacing = style.ItemSpacing.Y * 0.5f; + var descriptionSeparatorThickness = MathF.Max(1f, scale); + var descriptionSeparatorStart = windowPos + new Vector2(aliasColumnX - horizontalInset, descriptionStartLocal.Y); + var descriptionSeparatorEnd = new Vector2(windowPos.X + windowSize.X - style.WindowPadding.X + horizontalInset, descriptionSeparatorStart.Y); + drawList.AddLine(descriptionSeparatorStart, descriptionSeparatorEnd, ImGui.GetColorU32(portraitFrameBorder), descriptionSeparatorThickness); + + var descriptionContentStartLocal = descriptionStartLocal + new Vector2(0f, descriptionSeparatorThickness + descriptionSeparatorSpacing + style.FramePadding.Y * 0.75f); + ImGui.SetCursorPos(descriptionContentStartLocal); + ImGui.TextDisabled("Description"); + ImGui.SetCursorPosX(aliasColumnX); + var descriptionRegionWidth = ImGui.GetContentRegionAvail().X; + if (descriptionRegionWidth <= 0f) + descriptionRegionWidth = 1f; + var measurementWrapWidth = MathF.Max(1f, descriptionRegionWidth - style.WindowPadding.X * 2f); + var hasDescription = !string.IsNullOrWhiteSpace(profile.Description); + float descriptionContentHeight; + float lineHeightWithSpacing; + using (_uiSharedService.GameFont.Push()) + { + lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing(); + var measurementText = hasDescription + ? NormalizeDescriptionForMeasurement(profile.Description!) + : UserDescriptionPlaceholder; + if (string.IsNullOrWhiteSpace(measurementText)) + measurementText = UserDescriptionPlaceholder; + + descriptionContentHeight = ImGui.CalcTextSize(measurementText, wrapWidth: measurementWrapWidth).Y; + if (descriptionContentHeight <= 0f) + descriptionContentHeight = lineHeightWithSpacing; + } + + var maxDescriptionHeight = lineHeightWithSpacing * DescriptionMaxVisibleLines; + var descriptionChildHeight = Math.Clamp(descriptionContentHeight, lineHeightWithSpacing, maxDescriptionHeight); + + RenderDescriptionChild( + "##StandaloneProfileDescription", + new Vector2(descriptionRegionWidth, descriptionChildHeight), + hasDescription ? profile.Description : null, + UserDescriptionPlaceholder); + + var descriptionEndLocal = ImGui.GetCursorPos(); + var descriptionBlockBottom = windowPos.Y + descriptionEndLocal.Y; + aliasAndTagsBottomLocal = MathF.Max(aliasAndTagsBottomLocal, descriptionEndLocal.Y); + aliasAndTagsBlockBottom = MathF.Max(aliasAndTagsBlockBottom, descriptionBlockBottom); + + var presenceLabelSpacing = style.ItemSpacing.Y * 0.35f; + var presenceAnchorY = MathF.Max(portraitFrameLocalMax.Y, aliasGroupLocalMax.Y); + var presenceStartLocal = new Vector2( + portraitFrameLocalMin.X, + presenceAnchorY + presenceLabelSpacing); + ImGui.SetCursorPos(presenceStartLocal); + ImGui.TextDisabled("Presence"); + ImGui.SetCursorPosX(portraitFrameLocalMin.X); + if (presenceTokens.Count > 0) + { + var presenceColumnWidth = MathF.Max(1f, aliasColumnX - portraitFrameLocalMin.X - style.ItemSpacing.X); + RenderPresenceTokens(presenceTokens, scale, presenceColumnWidth); + } + else + { + ImGui.SetCursorPosX(portraitFrameLocalMin.X); + ImGui.TextDisabled("-- No presence information --"); + ImGui.SetCursorPosX(portraitFrameLocalMin.X); + ImGui.Dummy(new Vector2(0f, style.ItemSpacing.Y * 0.25f)); + } + + var presenceContentEnd = ImGui.GetCursorPos(); + var separatorSpacing = style.ItemSpacing.Y * 0.2f; + var separatorThickness = MathF.Max(1f, scale); + var separatorStartLocal = new Vector2(portraitFrameLocalMin.X, presenceContentEnd.Y + separatorSpacing); + var separatorStart = windowPos + separatorStartLocal; + var separatorEnd = new Vector2(portraitFrameMax.X, separatorStart.Y); + drawList.AddLine(separatorStart, separatorEnd, ImGui.GetColorU32(portraitFrameBorder), separatorThickness); + var afterSeparatorLocal = separatorStartLocal + new Vector2(0f, separatorThickness + separatorSpacing * 0.75f); + + var columnStartLocalY = afterSeparatorLocal.Y; + var leftColumnX = portraitFrameLocalMin.X; + var leftWrapPos = windowPos.X + aliasColumnX - style.ItemSpacing.X; + + ImGui.SetCursorPos(new Vector2(leftColumnX, columnStartLocalY)); + float leftColumnEndY = columnStartLocalY; + + if (!string.IsNullOrEmpty(noteText)) + { + ImGui.TextDisabled("Notes"); + ImGui.SetCursorPosX(leftColumnX); + ImGui.PushTextWrapPos(leftWrapPos); + ImGui.TextUnformatted(noteText); + ImGui.PopTextWrapPos(); + ImGui.SetCursorPos(new Vector2(leftColumnX, ImGui.GetCursorPosY() + style.ItemSpacing.Y * 0.5f)); + leftColumnEndY = ImGui.GetCursorPosY(); + } + + leftColumnEndY = MathF.Max(leftColumnEndY, ImGui.GetCursorPosY()); + + var columnsBottomLocal = leftColumnEndY; + var columnsBottom = windowPos.Y + columnsBottomLocal; + var topAreaBase = windowPos.Y + topAreaStart.Y; + var contentBlockBottom = MathF.Max(columnsBottom, aliasAndTagsBlockBottom); + var leftBlockBottom = MathF.Max(portraitBlockBottom, contentBlockBottom); + var topAreaHeight = leftBlockBottom - topAreaBase; + if (topAreaHeight < 0f) + topAreaHeight = 0f; + + ImGui.SetCursorPos(new Vector2(leftColumnX, topAreaStart.Y + topAreaHeight + style.ItemSpacing.Y)); + + var finalCursorY = ImGui.GetCursorPosY(); + var paddingY = ImGui.GetStyle().WindowPadding.Y; + var computedHeight = finalCursorY + paddingY; + var adjustedHeight = Math.Clamp(computedHeight, minHeight, maxAllowedHeight); + _lastComputedWindowHeight = adjustedHeight; + + var finalSize = new Vector2(baseWidth, adjustedHeight); + Size = finalSize; + ImGui.SetWindowSize(finalSize, ImGuiCond.Always); } catch (Exception ex) { - _logger.LogWarning(ex, "Error during draw tooltip"); + _logger.LogWarning(ex, "Error during standalone profile draw"); } } + private IDalamudTextureWrap? GetIconWrap(uint iconId) + { + try + { + if (_uiSharedService.TryGetIcon(iconId, out var wrap) && wrap != null) + return wrap; + } + catch (Exception ex) + { + _logger.LogDebug(ex, "Failed to resolve icon {IconId} for profile tags", iconId); + } + + return null; + } + + private void RenderDescriptionChild( + string childId, + Vector2 childSize, + string? description, + string placeholderText) + { + ImGui.PushStyleVar(ImGuiStyleVar.ChildBorderSize, 0f); + if (ImGui.BeginChild(childId, childSize, false)) + { + using (_uiSharedService.GameFont.Push()) + { + ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); + if (string.IsNullOrWhiteSpace(description)) + { + ImGui.TextUnformatted(placeholderText); + } + else if (!SeStringUtils.TryRenderSeStringMarkupAtCursor(description)) + { + ImGui.TextUnformatted(description); + } + ImGui.PopTextWrapPos(); + } + } + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + + private void RenderProfileTags(IReadOnlyList tags, float scale) + { + if (tags.Count == 0) + { + ImGui.TextDisabled("-- No tags set --"); + return; + } + + var drawList = ImGui.GetWindowDrawList(); + var style = ImGui.GetStyle(); + var defaultTextColorU32 = ImGui.GetColorU32(ImGuiCol.Text); + + var startLocal = ImGui.GetCursorPos(); + var startScreen = ImGui.GetCursorScreenPos(); + float availableWidth = ImGui.GetContentRegionAvail().X; + if (availableWidth <= 0f) + availableWidth = 1f; + + float cursorX = startScreen.X; + float cursorY = startScreen.Y; + float rowHeight = 0f; + + for (int i = 0; i < tags.Count; i++) + { + var tag = tags[i]; + if (!tag.HasContent) + continue; + + var tagSize = ProfileTagRenderer.MeasureTag(tag, scale, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _seResolvedSegments, GetIconWrap, _logger); + var tagWidth = tagSize.X; + var tagHeight = tagSize.Y; + + if (cursorX > startScreen.X && cursorX + tagWidth > startScreen.X + availableWidth) + { + cursorX = startScreen.X; + cursorY += rowHeight + style.ItemSpacing.Y; + rowHeight = 0f; + } + + var tagPos = new Vector2(cursorX, cursorY); + ImGui.SetCursorScreenPos(tagPos); + ImGui.InvisibleButton($"##profileTag_{i}", tagSize); + ProfileTagRenderer.RenderTag(tag, tagPos, scale, drawList, style, _tagBackgroundColor, _tagBorderColor, defaultTextColorU32, _seResolvedSegments, GetIconWrap, _logger); + + cursorX += tagWidth + style.ItemSpacing.X; + rowHeight = MathF.Max(rowHeight, tagHeight); + } + + var totalHeight = (cursorY + rowHeight) - startScreen.Y; + if (totalHeight < 0f) + totalHeight = 0f; + + ImGui.SetCursorPos(new Vector2(startLocal.X, startLocal.Y + totalHeight)); + } + + private void DrawGroupProfileWindow() + { + if (_groupInfo is null || _groupData is null) + return; + + var scale = ImGuiHelpers.GlobalScale; + var viewport = ImGui.GetMainViewport(); + var linked = ProfileEditorLayoutCoordinator.IsActive(_groupData.GID); + var baseSize = ProfileEditorLayoutCoordinator.GetProfileSize(scale); + var baseWidth = baseSize.X; + var minHeight = baseSize.Y; + var maxAllowedHeight = minHeight * MaxHeightMultiplier; + var targetHeight = _lastComputedWindowHeight > 0f + ? Math.Clamp(_lastComputedWindowHeight, minHeight, maxAllowedHeight) + : minHeight; + var desiredSize = new Vector2(baseWidth, targetHeight); + Size = desiredSize; + + if (linked) + { + ProfileEditorLayoutCoordinator.EnsureAnchor(viewport.WorkPos, scale); + + var currentPos = ImGui.GetWindowPos(); + if (IsWindowBeingDragged()) + ProfileEditorLayoutCoordinator.UpdateAnchorFromProfile(currentPos); + + var desiredPos = ProfileEditorLayoutCoordinator.GetProfilePosition(scale); + if (!ProfileEditorLayoutCoordinator.NearlyEquals(currentPos, desiredPos)) + ImGui.SetWindowPos(desiredPos, ImGuiCond.Always); + + if (!ProfileEditorLayoutCoordinator.NearlyEquals(ImGui.GetWindowSize(), desiredSize)) + ImGui.SetWindowSize(desiredSize, ImGuiCond.Always); + } + else + { + var defaultPosition = viewport.WorkPos + (new Vector2(50f, 70f) * scale); + ImGui.SetWindowPos(defaultPosition, ImGuiCond.FirstUseEver); + ImGui.SetWindowSize(desiredSize, ImGuiCond.Always); + } + + var profile = _lightlessProfileManager.GetLightlessGroupProfile(_groupData); + IReadOnlyList profileTags = profile.Tags.Count > 0 + ? _profileTagService.ResolveTags(profile.Tags) + : Array.Empty(); + + if (_textureWrap == null || !profile.ProfileImageData.Value.SequenceEqual(_lastProfilePicture)) + { + _textureWrap?.Dispose(); + _textureWrap = null; + _lastProfilePicture = profile.ProfileImageData.Value; + ResetBannerTexture(); + if (_lastProfilePicture.Length > 0) + { + _textureWrap = _uiSharedService.LoadImage(_lastProfilePicture); + } + } + + if (_supporterTextureWrap != null) + { + _supporterTextureWrap.Dispose(); + _supporterTextureWrap = null; + } + _lastSupporterPicture = Array.Empty(); + + var bannerBytes = profile.BannerImageData.Value; + if (!_lastBannerPicture.SequenceEqual(bannerBytes)) + { + ResetBannerTexture(); + _lastBannerPicture = bannerBytes; + } + + var noteText = _serverManager.GetNoteForGid(_groupData.GID); + + var presenceTokens = new List + { + new(profile.IsDisabled ? "Disabled" : "Active", profile.IsDisabled) + }; + + if (profile.IsNsfw) + presenceTokens.Add(new PresenceToken("NSFW", true)); + + int memberCount = 0; + List? groupMembers = null; + var snapshot = _pairUiService.GetSnapshot(); + var groupInfo = _groupInfo; + if (groupInfo is not null && snapshot.GroupsByGid.TryGetValue(groupInfo.GID, out var refreshedGroupInfo)) + { + groupInfo = refreshedGroupInfo; + } + if (groupInfo is not null && snapshot.GroupPairs.TryGetValue(groupInfo, out var pairsForGroup)) + { + groupMembers = pairsForGroup.ToList(); + memberCount = groupMembers.Count; + } + else if (groupInfo?.GroupPairUserInfos is { Count: > 0 }) + { + memberCount = groupInfo.GroupPairUserInfos.Count; + } + + string memberLabel = memberCount == 1 ? "1 Member" : $"{memberCount} Members"; + presenceTokens.Add(new PresenceToken(memberLabel, false)); + + if (groupInfo?.GroupPermissions.IsDisableInvites() ?? false) + { + presenceTokens.Add(new PresenceToken( + "Invites Locked", + true, + new[] + { + "New members cannot join while this lock is active." + }, + "Syncshell Status")); + } + + var drawList = ImGui.GetWindowDrawList(); + var style = ImGui.GetStyle(); + var windowPos = ImGui.GetWindowPos(); + var windowSize = ImGui.GetWindowSize(); + var bannerHeight = 260f * scale; + var portraitSize = new Vector2(180f, 180f) * scale; + var portraitBorder = 1.5f * scale; + var portraitRounding = 1f * scale; + var portraitFrameSize = portraitSize + new Vector2(portraitBorder * 2f); + var portraitOverlap = portraitSize.Y * 0.35f; + var portraitOffsetX = 35f * scale; + var infoOffsetX = portraitOffsetX + portraitFrameSize.X + style.ItemSpacing.X * 2f; + var bannerTexture = GetBannerTexture(_lastBannerPicture) ?? _textureWrap; + + var bannerScrollOffset = new Vector2(ImGui.GetScrollX(), ImGui.GetScrollY()); + var bannerMin = windowPos - bannerScrollOffset; + var bannerMax = bannerMin + new Vector2(windowSize.X, bannerHeight); + + if (bannerTexture != null) + { + drawList.AddImage( + bannerTexture.Handle, + bannerMin, + bannerMax); + } + else + { + var headerBase = ImGui.ColorConvertU32ToFloat4(ImGui.GetColorU32(ImGuiCol.Header)); + var topColor = ResolveThemeColor("ProfileBodyGradientTop", Vector4.Lerp(headerBase, Vector4.One, 0.25f)); + topColor.W = 1f; + var bottomColor = ResolveThemeColor("ProfileBodyGradientBottom", Vector4.Lerp(headerBase, Vector4.Zero, 0.35f)); + bottomColor.W = 1f; + + drawList.AddRectFilledMultiColor( + bannerMin, + bannerMax, + ImGui.ColorConvertFloat4ToU32(topColor), + ImGui.ColorConvertFloat4ToU32(topColor), + ImGui.ColorConvertFloat4ToU32(bottomColor), + ImGui.ColorConvertFloat4ToU32(bottomColor)); + } + + var contentStartY = MathF.Max(style.WindowPadding.Y, bannerHeight - portraitOverlap); + var topAreaStart = ImGui.GetCursorPos(); + + var portraitBackgroundPadding = 12f * scale; + var portraitAreaSize = portraitFrameSize + new Vector2(portraitBackgroundPadding * 2f); + var portraitAreaPos = new Vector2(style.WindowPadding.X + portraitOffsetX - portraitBackgroundPadding, contentStartY - portraitBackgroundPadding - 24f * scale); + + ImGui.SetCursorPos(portraitAreaPos); + var portraitAreaScreenPos = ImGui.GetCursorScreenPos(); + ImGui.Dummy(portraitAreaSize); + var contentStart = ImGui.GetCursorPos(); + + var portraitAreaMin = portraitAreaScreenPos; + var portraitAreaMax = portraitAreaMin + portraitAreaSize; + var portraitFrameMin = portraitAreaMin + new Vector2(portraitBackgroundPadding); + var portraitFrameMax = portraitFrameMin + portraitFrameSize; + + var portraitAreaColor = style.Colors[(int)ImGuiCol.WindowBg]; + portraitAreaColor.W = MathF.Min(1f, portraitAreaColor.W + 0.2f); + drawList.AddRectFilled(portraitAreaMin, portraitAreaMax, ImGui.GetColorU32(portraitAreaColor), portraitRounding + portraitBorder + portraitBackgroundPadding); + var portraitFrameBorder = style.Colors[(int)ImGuiCol.Border]; + + if (_textureWrap != null) + { + drawList.AddImageRounded( + _textureWrap.Handle, + portraitFrameMin + new Vector2(portraitBorder, portraitBorder), + portraitFrameMax - new Vector2(portraitBorder, portraitBorder), + Vector2.Zero, + Vector2.One, + 0xFFFFFFFF, + portraitRounding); + } + else + { + drawList.AddRect( + portraitFrameMin + new Vector2(portraitBorder, portraitBorder), + portraitFrameMax - new Vector2(portraitBorder, portraitBorder), + ImGui.GetColorU32(portraitFrameBorder), + portraitRounding); + } + + drawList.AddRect(portraitFrameMin, portraitFrameMax, ImGui.GetColorU32(portraitFrameBorder), portraitRounding); + var portraitAreaLocalMax = portraitAreaMax - windowPos; + var portraitFrameLocalMin = portraitFrameMin - windowPos; + var portraitFrameLocalMax = portraitFrameMax - windowPos; + var portraitBlockBottom = windowPos.Y + portraitAreaLocalMax.Y; + + ImGui.SetCursorPos(contentStart); + + bool useVanityColors = false; + Vector4? vanityTextColor = null; + Vector4? vanityGlowColor = null; + string primaryHeaderText = _groupInfo.GroupAliasOrGID; + + List<(string Text, bool UseVanityColor, bool Disabled)> secondaryHeaderLines = new() + { + (_groupData.GID, false, true) + }; + + if (_groupInfo.Owner is not null) + secondaryHeaderLines.Add(($"Owner: {_groupInfo.Owner.AliasOrUID}", false, true)); + + var infoStartY = MathF.Max(contentStartY, bannerHeight + style.WindowPadding.Y); + var aliasColumnX = infoOffsetX + 18f * scale; + ImGui.SetCursorPos(new Vector2(aliasColumnX, infoStartY)); + + ImGui.BeginGroup(); + using (_uiSharedService.UidFont.Push()) + { + ImGui.TextUnformatted(primaryHeaderText); + } + + foreach (var (text, useColor, disabled) in secondaryHeaderLines) + { + if (useColor && useVanityColors) + { + var seString = SeStringUtils.BuildFormattedPlayerName(text, vanityTextColor, vanityGlowColor); + SeStringUtils.RenderSeStringWithHitbox(seString, ImGui.GetCursorScreenPos(), ImGui.GetFont()); + } + else + { + if (disabled) + ImGui.TextDisabled(text); + else + ImGui.TextUnformatted(text); + } + } + ImGui.EndGroup(); + var namesEnd = ImGui.GetCursorPos(); + + var aliasGroupRectMin = ImGui.GetItemRectMin(); + var aliasGroupRectMax = ImGui.GetItemRectMax(); + var aliasGroupLocalMin = aliasGroupRectMin - windowPos; + var aliasGroupLocalMax = aliasGroupRectMax - windowPos; + + var tagsStartLocal = new Vector2(aliasGroupLocalMax.X + style.ItemSpacing.X + 25f * scale, aliasGroupLocalMin.Y + style.FramePadding.Y + 2f * scale); + ImGui.SetCursorPos(tagsStartLocal); + if (profileTags.Count > 0) + RenderProfileTags(profileTags, scale); + else + ImGui.TextDisabled("-- No tags set --"); + var tagsEndLocal = ImGui.GetCursorPos(); + var tagsBlockBottom = windowPos.Y + tagsEndLocal.Y; + var aliasBlockBottom = windowPos.Y + aliasGroupLocalMax.Y; + var aliasAndTagsBottomLocal = MathF.Max(aliasGroupLocalMax.Y, tagsEndLocal.Y); + var aliasAndTagsBlockBottom = MathF.Max(aliasBlockBottom, tagsBlockBottom); + + var descriptionSeparatorSpacing = style.ItemSpacing.Y * 0.35f; + var descriptionSeparatorThickness = MathF.Max(1f, scale); + var descriptionExtraOffset = _groupInfo.Owner is not null ? style.ItemSpacing.Y * 0.6f : 0f; + var descriptionStartLocal = new Vector2(aliasColumnX, aliasAndTagsBottomLocal + descriptionSeparatorSpacing + descriptionExtraOffset); + var horizontalInset = style.ItemSpacing.X * 0.5f; + var descriptionSeparatorStart = windowPos + new Vector2(aliasColumnX - horizontalInset, descriptionStartLocal.Y); + var descriptionSeparatorEnd = new Vector2(windowPos.X + windowSize.X - style.WindowPadding.X + horizontalInset, descriptionSeparatorStart.Y); + drawList.AddLine(descriptionSeparatorStart, descriptionSeparatorEnd, ImGui.GetColorU32(portraitFrameBorder), descriptionSeparatorThickness); + + var descriptionContentStartLocal = new Vector2(aliasColumnX, descriptionStartLocal.Y + descriptionSeparatorThickness + descriptionSeparatorSpacing + style.FramePadding.Y * 0.75f); + ImGui.SetCursorPos(descriptionContentStartLocal); + ImGui.TextDisabled("Description"); + ImGui.SetCursorPosX(aliasColumnX); + var descriptionRegionWidth = ImGui.GetContentRegionAvail().X; + if (descriptionRegionWidth <= 0f) + descriptionRegionWidth = 1f; + var measurementWrapWidth = MathF.Max(1f, descriptionRegionWidth - style.WindowPadding.X * 2f); + var hasDescription = !string.IsNullOrWhiteSpace(profile.Description); + float descriptionContentHeight; + float lineHeightWithSpacing; + using (_uiSharedService.GameFont.Push()) + { + lineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing(); + var measurementText = hasDescription + ? NormalizeDescriptionForMeasurement(profile.Description!) + : GroupDescriptionPlaceholder; + if (string.IsNullOrWhiteSpace(measurementText)) + measurementText = GroupDescriptionPlaceholder; + + descriptionContentHeight = ImGui.CalcTextSize(measurementText, wrapWidth: measurementWrapWidth).Y; + if (descriptionContentHeight <= 0f) + descriptionContentHeight = lineHeightWithSpacing; + } + + var maxDescriptionHeight = lineHeightWithSpacing * DescriptionMaxVisibleLines; + var descriptionChildHeight = Math.Clamp(descriptionContentHeight, lineHeightWithSpacing, maxDescriptionHeight); + + RenderDescriptionChild( + "##StandaloneGroupDescription", + new Vector2(descriptionRegionWidth, descriptionChildHeight), + hasDescription ? profile.Description : null, + GroupDescriptionPlaceholder); + var descriptionEndLocal = ImGui.GetCursorPos(); + var descriptionBlockBottom = windowPos.Y + descriptionEndLocal.Y; + aliasAndTagsBottomLocal = MathF.Max(aliasAndTagsBottomLocal, descriptionEndLocal.Y); + aliasAndTagsBlockBottom = MathF.Max(aliasAndTagsBlockBottom, descriptionBlockBottom); + + var presenceLabelSpacing = style.ItemSpacing.Y * 0.35f; + var presenceAnchorY = MathF.Max(portraitFrameLocalMax.Y, aliasGroupLocalMax.Y); + var presenceStartLocal = new Vector2(portraitFrameLocalMin.X, presenceAnchorY + presenceLabelSpacing); + ImGui.SetCursorPos(presenceStartLocal); + ImGui.TextDisabled("Presence"); + ImGui.SetCursorPosX(portraitFrameLocalMin.X); + if (presenceTokens.Count > 0) + { + var presenceColumnWidth = MathF.Max(1f, aliasColumnX - portraitFrameLocalMin.X - style.ItemSpacing.X); + RenderPresenceTokens(presenceTokens, scale, presenceColumnWidth); + } + else + { + ImGui.TextDisabled("-- No status flags --"); + ImGui.Dummy(new Vector2(0f, style.ItemSpacing.Y * 0.25f)); + } + + var presenceContentEnd = ImGui.GetCursorPos(); + var separatorSpacing = style.ItemSpacing.Y * 0.2f; + var separatorThickness = MathF.Max(1f, scale); + var separatorStartLocal = new Vector2(portraitFrameLocalMin.X, presenceContentEnd.Y + separatorSpacing); + var separatorStart = windowPos + separatorStartLocal; + var separatorEnd = new Vector2(portraitFrameMax.X, separatorStart.Y); + drawList.AddLine(separatorStart, separatorEnd, ImGui.GetColorU32(portraitFrameBorder), separatorThickness); + var afterSeparatorLocal = separatorStartLocal + new Vector2(0f, separatorThickness + separatorSpacing * 0.75f); + + var columnStartLocalY = afterSeparatorLocal.Y; + var leftColumnX = portraitFrameLocalMin.X; + ImGui.SetCursorPos(new Vector2(leftColumnX, columnStartLocalY)); + float leftColumnEndY = columnStartLocalY; + + if (!string.IsNullOrEmpty(noteText)) + { + ImGui.TextDisabled("Notes"); + ImGui.SetCursorPosX(leftColumnX); + ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + ImGui.GetContentRegionAvail().X); + ImGui.TextUnformatted(noteText); + ImGui.PopTextWrapPos(); + ImGui.SetCursorPos(new Vector2(leftColumnX, ImGui.GetCursorPosY() + style.ItemSpacing.Y * 0.5f)); + leftColumnEndY = ImGui.GetCursorPosY(); + } + + leftColumnEndY = MathF.Max(leftColumnEndY, ImGui.GetCursorPosY()); + + var columnsBottomLocal = leftColumnEndY; + var columnsBottom = windowPos.Y + columnsBottomLocal; + var topAreaBase = windowPos.Y + topAreaStart.Y; + var contentBlockBottom = MathF.Max(columnsBottom, aliasAndTagsBlockBottom); + var leftBlockBottom = MathF.Max(portraitBlockBottom, contentBlockBottom); + var topAreaHeight = leftBlockBottom - topAreaBase; + if (topAreaHeight < 0f) + topAreaHeight = 0f; + + ImGui.SetCursorPos(new Vector2(leftColumnX, topAreaStart.Y + topAreaHeight + style.ItemSpacing.Y)); + + var finalCursorY = ImGui.GetCursorPosY(); + var paddingY = ImGui.GetStyle().WindowPadding.Y; + var computedHeight = finalCursorY + paddingY; + var adjustedHeight = Math.Clamp(computedHeight, minHeight, maxAllowedHeight); + _lastComputedWindowHeight = adjustedHeight; + + var finalSize = new Vector2(baseWidth, adjustedHeight); + Size = finalSize; + ImGui.SetWindowSize(finalSize, ImGuiCond.Always); + } + + private IDalamudTextureWrap? GetBannerTexture(byte[] bannerBytes) + { + if (_bannerTextureLoaded) + return _bannerTextureWrap; + + _bannerTextureLoaded = true; + + if (bannerBytes.Length == 0) + return null; + + _bannerTextureWrap = _uiSharedService.LoadImage(bannerBytes); + return _bannerTextureWrap; + } + + private void ResetBannerTexture() + { + _bannerTextureWrap?.Dispose(); + _bannerTextureWrap = null; + _lastBannerPicture = []; + _bannerTextureLoaded = false; + } + + private static bool IsWindowBeingDragged() + { + return ImGui.IsWindowFocused(ImGuiFocusedFlags.RootAndChildWindows) && ImGui.GetIO().MouseDown[0]; + } + + private static string NormalizeDescriptionForMeasurement(string description) + { + if (string.IsNullOrWhiteSpace(description)) + return string.Empty; + + var normalized = description.ReplaceLineEndings("\n"); + normalized = normalized + .Replace("
", "\n", StringComparison.OrdinalIgnoreCase) + .Replace("
", "\n", StringComparison.OrdinalIgnoreCase) + .Replace("
", "\n", StringComparison.OrdinalIgnoreCase) + .Replace("
", "\n", StringComparison.OrdinalIgnoreCase); + + return SeStringUtils.StripMarkup(normalized); + } + private static void RenderPresenceTokens(IReadOnlyList tokens, float scale, float? maxWidth = null) + { + if (tokens.Count == 0) + return; + + var drawList = ImGui.GetWindowDrawList(); + var style = ImGui.GetStyle(); + + var startPos = ImGui.GetCursorPos(); + float startX = startPos.X; + float cursorX = startX; + float cursorY = startPos.Y; + float availWidth = maxWidth ?? ImGui.GetContentRegionAvail().X; + if (availWidth <= 0f) + availWidth = ImGui.GetContentRegionAvail().X; + if (availWidth <= 0f) + availWidth = 1f; + float spacingX = style.ItemSpacing.X; + float spacingY = style.ItemSpacing.Y; + float rounding = style.FrameRounding > 0f ? style.FrameRounding : 6f * scale; + + var padding = new Vector2(8f * scale, 4f * scale); + var baseColor = new Vector4(0.16f, 0.16f, 0.16f, 0.95f); + var baseBorder = style.Colors[(int)ImGuiCol.Border]; + baseBorder.W *= 0.35f; + var alertColor = new Vector4(0.32f, 0.2f, 0.2f, 0.95f); + var alertBorder = Vector4.Lerp(baseBorder, new Vector4(0.9f, 0.5f, 0.5f, baseBorder.W), 0.6f); + var textColor = style.Colors[(int)ImGuiCol.Text]; + + float rowHeight = 0f; + + for (int i = 0; i < tokens.Count; i++) + { + var token = tokens[i]; + var textSize = ImGui.CalcTextSize(token.Text); + var tagSize = textSize + padding * 2f; + + if (cursorX > startX && cursorX + tagSize.X > startX + availWidth) + { + cursorX = startX; + cursorY += rowHeight + spacingY; + rowHeight = 0f; + } + + ImGui.SetCursorPos(new Vector2(cursorX, cursorY)); + ImGui.InvisibleButton($"##presenceTag_{i}", tagSize); + + var tagMin = ImGui.GetItemRectMin(); + var tagMax = ImGui.GetItemRectMax(); + + var fillColor = token.Emphasis ? alertColor : baseColor; + var borderColor = token.Emphasis ? alertBorder : baseBorder; + + drawList.AddRectFilled(tagMin, tagMax, ImGui.GetColorU32(fillColor), rounding); + drawList.AddRect(tagMin, tagMax, ImGui.GetColorU32(borderColor), rounding); + drawList.AddText(tagMin + padding, ImGui.GetColorU32(textColor), token.Text); + + if (token.Tooltip is { Count: > 0 }) + { + if (ImGui.IsItemHovered()) + { + ImGui.BeginTooltip(); + if (!string.IsNullOrEmpty(token.TooltipTitle)) + { + ImGui.TextUnformatted(token.TooltipTitle); + ImGui.Separator(); + } + + foreach (var line in token.Tooltip) + ImGui.TextUnformatted(line); + ImGui.EndTooltip(); + } + } + + cursorX += tagSize.X + spacingX; + rowHeight = MathF.Max(rowHeight, tagSize.Y); + } + + ImGui.SetCursorPos(new Vector2(startX, cursorY + rowHeight)); + ImGui.Dummy(new Vector2(0f, spacingY * 0.25f)); + } + public override void OnClose() { + if (!_isGroupProfile + && !_isLightfinderContext + && Pair is null + && _userData is not null + && ProfileEditorLayoutCoordinator.IsActive(_userData.UID)) + { + ProfileEditorLayoutCoordinator.Disable(_userData.UID); + } + else if (_isGroupProfile + && _groupData is not null + && ProfileEditorLayoutCoordinator.IsActive(_groupData.GID)) + { + ProfileEditorLayoutCoordinator.Disable(_groupData.GID); + } Mediator.Publish(new RemoveWindowMessage(this)); } + + private readonly record struct PresenceToken( + string Text, + bool Emphasis, + IReadOnlyList? Tooltip = null, + string? TooltipTitle = null); } \ No newline at end of file diff --git a/LightlessSync/UI/Style/MainStyle.cs b/LightlessSync/UI/Style/MainStyle.cs index d3d8b68..3da7455 100644 --- a/LightlessSync/UI/Style/MainStyle.cs +++ b/LightlessSync/UI/Style/MainStyle.cs @@ -38,7 +38,7 @@ internal static class MainStyle new("color.border", "Border", () => Rgba(65, 65, 65, 255), ImGuiCol.Border), new("color.borderShadow", "Border Shadow", () => Rgba(0, 0, 0, 150), ImGuiCol.BorderShadow), new("color.frameBg", "Frame Background", () => Rgba(40, 40, 40, 255), ImGuiCol.FrameBg), - new("color.frameBgHovered", "Frame Background (Hover)", () => Rgba(50, 50, 50, 255), ImGuiCol.FrameBgHovered), + new("color.frameBgHovered", "Frame Background (Hover)", () => Rgba(50, 50, 50, 100), ImGuiCol.FrameBgHovered), new("color.frameBgActive", "Frame Background (Active)", () => Rgba(30, 30, 30, 255), ImGuiCol.FrameBgActive), new("color.titleBg", "Title Background", () => Rgba(24, 24, 24, 232), ImGuiCol.TitleBg), new("color.titleBgActive", "Title Background (Active)", () => Rgba(30, 30, 30, 255), ImGuiCol.TitleBgActive), diff --git a/LightlessSync/UI/Style/Selune.cs b/LightlessSync/UI/Style/Selune.cs new file mode 100644 index 0000000..f89a1f0 --- /dev/null +++ b/LightlessSync/UI/Style/Selune.cs @@ -0,0 +1,1006 @@ +using System; +using System.Numerics; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Utility; +using LightlessSync.UI; + +// imagine putting this goober name here + +namespace LightlessSync.UI.Style; + +public enum SeluneGradientMode +{ + Vertical, + Horizontal, + Both, +} + +public enum SeluneHighlightMode +{ + Horizontal, + Vertical, + Both, + Point, +} + +public sealed class SeluneGradientSettings +{ + public Vector4 GradientColor { get; init; } = UIColors.Get("LightlessPurple"); + public Vector4? HighlightColor { get; init; } + public float GradientPeakOpacity { get; init; } = 0.07f; + public float HighlightPeakAlpha { get; init; } = 0.13f; + public float HighlightEdgeAlpha { get; init; } = 0f; + public float HighlightMidpoint { get; init; } = 0.45f; + public float MinimumHighlightHalfHeight { get; init; } = 25f; + public float MinimumHighlightHalfWidth { get; init; } = 25f; + public float HighlightFadeInSpeed { get; init; } = 14f; + public float HighlightFadeOutSpeed { get; init; } = 8f; + public float HighlightBorderThickness { get; init; } = 10f; + public float HighlightBorderRounding { get; init; } = 8f; + public SeluneGradientMode BackgroundMode { get; init; } = SeluneGradientMode.Vertical; + public SeluneHighlightMode HighlightMode { get; init; } = SeluneHighlightMode.Horizontal; + + public static SeluneGradientSettings Default + => new() + { + GradientColor = UIColors.Get("LightlessPurple"), + HighlightColor = UIColors.Get("LightlessPurple"), + }; +} + +public static class Selune +{ + [ThreadStatic] private static SeluneCanvas? _activeCanvas; + + public static SeluneCanvas Begin(SeluneBrush brush, ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, SeluneGradientSettings? settings = null) + { + var canvas = new SeluneCanvas(brush, drawList, windowPos, windowSize, settings ?? SeluneGradientSettings.Default, _activeCanvas); + _activeCanvas = canvas; + return canvas; + } + + internal static void Release(SeluneCanvas canvas) + { + if (_activeCanvas == canvas) + _activeCanvas = canvas.Previous; + } + + public static void RegisterHighlight( + Vector2 rectMin, + Vector2 rectMax, + SeluneHighlightMode? modeOverride = null, + bool borderOnly = false, + float? borderThicknessOverride = null, + bool exactSize = false, + bool clipToElement = false, + Vector2? clipPadding = null, + float? roundingOverride = null, + bool spanFullWidth = false, + Vector4? highlightColorOverride = null, + float? highlightAlphaOverride = null) + => _activeCanvas?.RegisterHighlight( + rectMin, + rectMax, + modeOverride, + borderOnly, + borderThicknessOverride, + exactSize, + clipToElement, + clipPadding, + roundingOverride, + spanFullWidth, + highlightColorOverride, + highlightAlphaOverride); +} + +public sealed class SeluneBrush +{ + private Vector2? _highlightCenter; + private Vector2 _highlightHalfSize; + private SeluneHighlightMode _highlightMode; + private bool _highlightBorderOnly; + private float _borderThickness; + private bool _useClipRect; + private Vector2 _clipMin; + private Vector2 _clipMax; + private float _highlightRounding; + private bool _highlightUsedThisFrame; + private float _highlightIntensity; + private Vector4? _highlightColorOverride; + private float? _highlightAlphaOverride; + + internal void BeginFrame() + { + _highlightUsedThisFrame = false; + } + + internal void RegisterHighlight(Vector2 center, Vector2 halfSize, SeluneHighlightMode mode, bool borderOnly, float borderThickness, bool useClipRect, Vector2 clipMin, Vector2 clipMax, float rounding, Vector4? highlightColorOverride, float? highlightAlphaOverride) + { + if (halfSize.X <= 0f || halfSize.Y <= 0f) + return; + + _highlightUsedThisFrame = true; + _highlightCenter = center; + _highlightHalfSize = halfSize; + _highlightMode = mode; + _highlightBorderOnly = borderOnly; + _borderThickness = borderOnly ? Math.Max(borderThickness, 0f) : 0f; + _useClipRect = useClipRect; + _clipMin = clipMin; + _clipMax = clipMax; + _highlightRounding = rounding; + _highlightColorOverride = highlightColorOverride; + _highlightAlphaOverride = highlightAlphaOverride; + } + + internal void UpdateFade(float deltaTime, SeluneGradientSettings settings) + { + if (deltaTime <= 0f) + return; + + if (_highlightUsedThisFrame) + { + _highlightIntensity = MathF.Min(1f, _highlightIntensity + deltaTime * settings.HighlightFadeInSpeed); + } + else + { + _highlightIntensity = MathF.Max(0f, _highlightIntensity - deltaTime * settings.HighlightFadeOutSpeed); + + if (_highlightIntensity <= 0.001f) + { + ResetHighlightState(); + } + } + } + + internal SeluneHighlightRenderState GetRenderState() + => new( + _highlightCenter, + _highlightHalfSize, + _highlightMode, + _highlightBorderOnly, + _borderThickness, + _useClipRect, + _clipMin, + _clipMax, + _highlightRounding, + _highlightIntensity, + _highlightColorOverride, + _highlightAlphaOverride); + + private void ResetHighlightState() + { + _highlightCenter = null; + _highlightHalfSize = Vector2.Zero; + _highlightBorderOnly = false; + _borderThickness = 0f; + _useClipRect = false; + _highlightRounding = 0f; + _highlightColorOverride = null; + _highlightAlphaOverride = null; + } +} + +internal readonly struct SeluneHighlightRenderState +{ + public SeluneHighlightRenderState( + Vector2? center, + Vector2 halfSize, + SeluneHighlightMode mode, + bool borderOnly, + float borderThickness, + bool useClipRect, + Vector2 clipMin, + Vector2 clipMax, + float rounding, + float intensity, + Vector4? colorOverride, + float? alphaOverride) + { + Center = center; + HalfSize = halfSize; + Mode = mode; + BorderOnly = borderOnly; + BorderThickness = borderThickness; + UseClipRect = useClipRect; + ClipMin = clipMin; + ClipMax = clipMax; + Rounding = rounding; + Intensity = intensity; + ColorOverride = colorOverride; + AlphaOverride = alphaOverride; + } + + public Vector2? Center { get; } + public Vector2 HalfSize { get; } + public SeluneHighlightMode Mode { get; } + public bool BorderOnly { get; } + public float BorderThickness { get; } + public bool UseClipRect { get; } + public Vector2 ClipMin { get; } + public Vector2 ClipMax { get; } + public float Rounding { get; } + public float Intensity { get; } + public Vector4? ColorOverride { get; } + public float? AlphaOverride { get; } + + public bool HasHighlight => Center.HasValue && HalfSize.X > 0f && HalfSize.Y > 0f && Intensity > 0.001f; +} + +public sealed class SeluneCanvas : IDisposable +{ + private readonly SeluneBrush _brush; + private readonly ImDrawListPtr _drawList; + private readonly Vector2 _windowPos; + private readonly Vector2 _windowSize; + private readonly SeluneGradientSettings _settings; + private bool _fadeUpdatedThisFrame; + + internal SeluneCanvas? Previous { get; } + + internal SeluneCanvas(SeluneBrush brush, ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, SeluneGradientSettings settings, SeluneCanvas? previous) + { + _brush = brush; + _drawList = drawList; + _windowPos = windowPos; + _windowSize = windowSize; + _settings = settings; + Previous = previous; + _fadeUpdatedThisFrame = false; + + _brush.BeginFrame(); + } + + public void DrawGradient(float gradientTopY, float gradientBottomY, float deltaTime) + { + DrawInternal(gradientTopY, gradientBottomY, deltaTime, true, true); + } + + public void DrawHighlightOnly(float gradientTopY, float gradientBottomY, float deltaTime) + { + DrawInternal(gradientTopY, gradientBottomY, deltaTime, false, true); + } + + public void DrawHighlightOnly(float deltaTime) + => DrawHighlightOnly(_windowPos.Y, _windowPos.Y + _windowSize.Y, deltaTime); + + public void Animate(float deltaTime) + { + UpdateFadeOnce(deltaTime); + } + + private void UpdateFadeOnce(float deltaTime) + { + if (_fadeUpdatedThisFrame) + return; + + _brush.UpdateFade(deltaTime, _settings); + _fadeUpdatedThisFrame = true; + } + + private void DrawInternal(float gradientTopY, float gradientBottomY, float deltaTime, bool drawBackground, bool drawHighlight) + { + UpdateFadeOnce(deltaTime); + + SeluneRenderer.DrawGradient( + _drawList, + _windowPos, + _windowSize, + gradientTopY, + gradientBottomY, + _brush.GetRenderState(), + _settings, + drawBackground, + drawHighlight); + } + + internal void RegisterHighlight( + Vector2 rectMin, + Vector2 rectMax, + SeluneHighlightMode? modeOverride, + bool borderOnly, + float? borderThicknessOverride, + bool exactSize, + bool clipToElement, + Vector2? clipPadding, + float? roundingOverride, + bool spanFullWidth, + Vector4? highlightColorOverride, + float? highlightAlphaOverride) + { + if (spanFullWidth) + { + rectMin.X = _windowPos.X; + rectMax.X = _windowPos.X + _windowSize.X; + } + + var size = rectMax - rectMin; + if (size.X <= 0f || size.Y <= 0f) + return; + + var center = rectMin + size * 0.5f; + var halfWidth = exactSize ? size.X * 0.5f : Math.Max(size.X * 0.5f, _settings.MinimumHighlightHalfWidth * ImGuiHelpers.GlobalScale); + var halfHeight = exactSize ? size.Y * 0.5f : Math.Max(size.Y * 0.5f, _settings.MinimumHighlightHalfHeight * ImGuiHelpers.GlobalScale); + var mode = modeOverride ?? _settings.HighlightMode; + var thickness = borderOnly ? (borderThicknessOverride ?? _settings.HighlightBorderThickness) * ImGuiHelpers.GlobalScale : 0f; + var useClip = clipToElement; + var padding = clipPadding ?? (borderOnly && thickness > 0f + ? new Vector2(thickness) + : Vector2.Zero); + var clipMin = rectMin - padding; + var clipMax = rectMax + padding; + var rounding = (roundingOverride ?? _settings.HighlightBorderRounding) * ImGuiHelpers.GlobalScale; + + _brush.RegisterHighlight(center, new Vector2(halfWidth, halfHeight), mode, borderOnly, thickness, useClip, clipMin, clipMax, rounding, highlightColorOverride, highlightAlphaOverride); + _fadeUpdatedThisFrame = false; + } + + public void Dispose() + => Selune.Release(this); +} + // i wonder which sync will copy this shitty code now +internal static class SeluneRenderer +{ + public static void DrawGradient( + ImDrawListPtr drawList, + Vector2 windowPos, + Vector2 windowSize, + float gradientTopY, + float gradientBottomY, + SeluneHighlightRenderState highlightState, + SeluneGradientSettings settings, + bool drawBackground = true, + bool drawHighlight = true) + { + var gradientLeft = windowPos.X; + var gradientRight = windowPos.X + windowSize.X; + var windowBottomY = windowPos.Y + windowSize.Y; + var clampedTopY = MathF.Max(gradientTopY, windowPos.Y); + var clampedBottomY = MathF.Min(gradientBottomY, windowBottomY); + + if (clampedBottomY <= clampedTopY) + return; + + var color = settings.GradientColor; + var topColorVec = new Vector4(color.X, color.Y, color.Z, 0f); + var bottomColorVec = new Vector4(color.X, color.Y, color.Z, 0f); + var midColorVec = new Vector4(color.X, color.Y, color.Z, settings.GradientPeakOpacity); + + if (drawBackground) + { + DrawBackground( + drawList, + gradientLeft, + gradientRight, + clampedTopY, + clampedBottomY, + topColorVec, + midColorVec, + bottomColorVec, + settings.BackgroundMode); + } + + if (!drawHighlight) + return; + + DrawHighlight( + drawList, + gradientLeft, + gradientRight, + clampedTopY, + clampedBottomY, + highlightState, + settings); + } + + private static void DrawBackground( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + Vector4 topColorVec, + Vector4 midColorVec, + Vector4 bottomColorVec, + SeluneGradientMode mode) + { + switch (mode) + { + case SeluneGradientMode.Vertical: + DrawVerticalBackground(drawList, gradientLeft, gradientRight, clampedTopY, clampedBottomY, topColorVec, midColorVec, bottomColorVec); + break; + case SeluneGradientMode.Horizontal: + DrawHorizontalBackground(drawList, gradientLeft, gradientRight, clampedTopY, clampedBottomY, topColorVec, midColorVec, bottomColorVec); + break; + case SeluneGradientMode.Both: + DrawVerticalBackground(drawList, gradientLeft, gradientRight, clampedTopY, clampedBottomY, topColorVec, midColorVec, bottomColorVec); + DrawHorizontalBackground(drawList, gradientLeft, gradientRight, clampedTopY, clampedBottomY, topColorVec, midColorVec, bottomColorVec); + break; + } + } + + private static void DrawVerticalBackground( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + Vector4 topColorVec, + Vector4 midColorVec, + Vector4 bottomColorVec) + { + var topColor = ImGui.ColorConvertFloat4ToU32(topColorVec); + var midColor = ImGui.ColorConvertFloat4ToU32(midColorVec); + var bottomColor = ImGui.ColorConvertFloat4ToU32(bottomColorVec); + + var midY = clampedTopY + (clampedBottomY - clampedTopY) * 0.035f; + drawList.AddRectFilledMultiColor( + new Vector2(gradientLeft, clampedTopY), + new Vector2(gradientRight, midY), + topColor, + topColor, + midColor, + midColor); + + drawList.AddRectFilledMultiColor( + new Vector2(gradientLeft, midY), + new Vector2(gradientRight, clampedBottomY), + midColor, + midColor, + bottomColor, + bottomColor); + } + + private static void DrawHorizontalBackground( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + Vector4 leftColorVec, + Vector4 midColorVec, + Vector4 rightColorVec) + { + var leftColor = ImGui.ColorConvertFloat4ToU32(leftColorVec); + var midColor = ImGui.ColorConvertFloat4ToU32(midColorVec); + var rightColor = ImGui.ColorConvertFloat4ToU32(rightColorVec); + + var midX = gradientLeft + (gradientRight - gradientLeft) * 0.035f; + drawList.AddRectFilledMultiColor( + new Vector2(gradientLeft, clampedTopY), + new Vector2(midX, clampedBottomY), + leftColor, + midColor, + midColor, + leftColor); + + drawList.AddRectFilledMultiColor( + new Vector2(midX, clampedTopY), + new Vector2(gradientRight, clampedBottomY), + midColor, + rightColor, + rightColor, + midColor); + } + + private static void DrawHighlight( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + SeluneHighlightRenderState highlightState, + SeluneGradientSettings settings) + { + if (!highlightState.HasHighlight) + return; + + var highlightColor = highlightState.ColorOverride ?? settings.HighlightColor ?? settings.GradientColor; + var clampedIntensity = Math.Clamp(highlightState.Intensity, 0f, 1f); + var alphaScale = Math.Clamp(highlightState.AlphaOverride ?? 1f, 0f, 1f); + var peakAlpha = settings.HighlightPeakAlpha * clampedIntensity * alphaScale; + var edgeAlpha = settings.HighlightEdgeAlpha * clampedIntensity * alphaScale; + + if (peakAlpha <= 0f && edgeAlpha <= 0f) + return; + + var highlightEdgeVec = new Vector4(highlightColor.X, highlightColor.Y, highlightColor.Z, edgeAlpha); + var highlightPeakVec = new Vector4(highlightColor.X, highlightColor.Y, highlightColor.Z, peakAlpha); + var center = highlightState.Center!.Value; + var halfSize = highlightState.HalfSize; + + if (highlightState.UseClipRect) + drawList.PushClipRect(highlightState.ClipMin, highlightState.ClipMax, true); + + switch (highlightState.Mode) + { + case SeluneHighlightMode.Horizontal: + DrawHorizontalHighlight( + drawList, + gradientLeft, + gradientRight, + clampedTopY, + clampedBottomY, + center, + halfSize, + highlightEdgeVec, + highlightPeakVec, + settings.HighlightMidpoint, + highlightState.BorderOnly, + highlightState.BorderThickness, + highlightState.Rounding); + break; + + case SeluneHighlightMode.Vertical: + DrawVerticalHighlight( + drawList, + gradientLeft, + gradientRight, + clampedTopY, + clampedBottomY, + center, + halfSize, + highlightEdgeVec, + highlightPeakVec, + settings.HighlightMidpoint, + highlightState.BorderOnly, + highlightState.BorderThickness, + highlightState.Rounding); + break; + + case SeluneHighlightMode.Both: + DrawCombinedHighlight( + drawList, + gradientLeft, + gradientRight, + clampedTopY, + clampedBottomY, + center, + halfSize, + highlightEdgeVec, + highlightPeakVec, + highlightState.BorderOnly, + highlightState.BorderThickness, + highlightState.Rounding); + break; + + case SeluneHighlightMode.Point: + DrawPointHighlight( + drawList, + center, + halfSize, + highlightEdgeVec, + highlightPeakVec, + highlightState.BorderOnly, + highlightState.BorderThickness); + break; + } + + if (highlightState.UseClipRect) + drawList.PopClipRect(); + } + + private static void DrawHorizontalHighlight( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + Vector2 center, + Vector2 halfSize, + Vector4 edgeColor, + Vector4 peakColor, + float midpoint, + bool borderOnly, + float borderThickness, + float rounding) + { + var highlightTop = MathF.Max(clampedTopY, center.Y - halfSize.Y); + var highlightBottom = MathF.Min(clampedBottomY, center.Y + halfSize.Y); + if (highlightBottom <= highlightTop) + return; + + var highlightLeft = MathF.Max(gradientLeft, center.X - halfSize.X); + var highlightRight = MathF.Min(gradientRight, center.X + halfSize.X); + + if (highlightRight <= highlightLeft || highlightBottom <= highlightTop) + return; + + if (!borderOnly || borderThickness <= 0f) + { + DrawHorizontalHighlightRect( + drawList, + highlightLeft, + highlightRight, + highlightTop, + highlightBottom, + edgeColor, + peakColor, + midpoint, + 1f); + return; + } + + var innerTop = MathF.Min(highlightBottom, MathF.Max(highlightTop, center.Y - MathF.Max(halfSize.Y - borderThickness, 0f))); + var innerBottom = MathF.Max(highlightTop, MathF.Min(highlightBottom, center.Y + MathF.Max(halfSize.Y - borderThickness, 0f))); + var edgeU32 = ImGui.ColorConvertFloat4ToU32(edgeColor); + var peakU32 = ImGui.ColorConvertFloat4ToU32(peakColor); + + if (innerTop > highlightTop) + { + drawList.AddRectFilledMultiColor( + new Vector2(highlightLeft, highlightTop), + new Vector2(highlightRight, innerTop), + edgeU32, + edgeU32, + peakU32, + peakU32); + } + + if (innerBottom < highlightBottom) + { + drawList.AddRectFilledMultiColor( + new Vector2(highlightLeft, innerBottom), + new Vector2(highlightRight, highlightBottom), + peakU32, + peakU32, + edgeU32, + edgeU32); + } + } + + private static void DrawVerticalHighlight( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + Vector2 center, + Vector2 halfSize, + Vector4 edgeColor, + Vector4 peakColor, + float midpoint, + bool borderOnly, + float borderThickness, + float rounding) + { + var highlightTop = MathF.Max(clampedTopY, center.Y - halfSize.Y); + var highlightBottom = MathF.Min(clampedBottomY, center.Y + halfSize.Y); + var highlightLeft = MathF.Max(gradientLeft, center.X - halfSize.X); + var highlightRight = MathF.Min(gradientRight, center.X + halfSize.X); + + if (highlightRight <= highlightLeft || highlightBottom <= highlightTop) + return; + + if (!borderOnly || borderThickness <= 0f) + { + DrawVerticalHighlightRect( + drawList, + highlightLeft, + highlightRight, + highlightTop, + highlightBottom, + edgeColor, + peakColor, + midpoint, + 1f); + return; + } + + var innerLeft = MathF.Min(highlightRight, MathF.Max(highlightLeft, center.X - MathF.Max(halfSize.X - borderThickness, 0f))); + var innerRight = MathF.Max(highlightLeft, MathF.Min(highlightRight, center.X + MathF.Max(halfSize.X - borderThickness, 0f))); + var edgeU32 = ImGui.ColorConvertFloat4ToU32(edgeColor); + var peakU32 = ImGui.ColorConvertFloat4ToU32(peakColor); + + if (innerLeft > highlightLeft) + { + drawList.AddRectFilledMultiColor( + new Vector2(highlightLeft, highlightTop), + new Vector2(innerLeft, highlightBottom), + edgeU32, + peakU32, + peakU32, + edgeU32); + } + + if (innerRight < highlightRight) + { + drawList.AddRectFilledMultiColor( + new Vector2(innerRight, highlightTop), + new Vector2(highlightRight, highlightBottom), + peakU32, + edgeU32, + edgeU32, + peakU32); + } + } + + private static void DrawCombinedHighlight( + ImDrawListPtr drawList, + float gradientLeft, + float gradientRight, + float clampedTopY, + float clampedBottomY, + Vector2 center, + Vector2 halfSize, + Vector4 edgeColor, + Vector4 peakColor, + bool borderOnly, + float borderThickness, + float rounding) + { + var highlightLeft = MathF.Max(gradientLeft, center.X - halfSize.X); + var highlightRight = MathF.Min(gradientRight, center.X + halfSize.X); + var highlightTop = MathF.Max(clampedTopY, center.Y - halfSize.Y); + var highlightBottom = MathF.Min(clampedBottomY, center.Y + halfSize.Y); + + if (highlightRight <= highlightLeft || highlightBottom <= highlightTop) + return; + + if (borderOnly && borderThickness > 0f) + { + DrawRoundedBorderGlow(drawList, center, halfSize, borderThickness, edgeColor, peakColor, rounding); + return; + } + + if (!borderOnly || borderThickness <= 0f) + { + const float combinedScale = 0.85f; + DrawHorizontalHighlightRect( + drawList, + highlightLeft, + highlightRight, + highlightTop, + highlightBottom, + edgeColor, + peakColor, + 0.5f, + combinedScale); + + DrawVerticalHighlightRect( + drawList, + highlightLeft, + highlightRight, + highlightTop, + highlightBottom, + edgeColor, + peakColor, + 0.5f, + combinedScale); + return; + } + + var outerLeft = MathF.Max(gradientLeft, highlightLeft - borderThickness); + var outerRight = MathF.Min(gradientRight, highlightRight + borderThickness); + var outerTop = MathF.Max(clampedTopY, highlightTop - borderThickness); + var outerBottom = MathF.Min(clampedBottomY, highlightBottom + borderThickness); + + var edge = ImGui.ColorConvertFloat4ToU32(edgeColor); + var peak = ImGui.ColorConvertFloat4ToU32(peakColor); + + if (outerTop < highlightTop) + { + drawList.AddRectFilledMultiColor( + new Vector2(outerLeft, outerTop), + new Vector2(outerRight, highlightTop), + edge, + edge, + peak, + peak); + } + + if (outerBottom > highlightBottom) + { + drawList.AddRectFilledMultiColor( + new Vector2(outerLeft, highlightBottom), + new Vector2(outerRight, outerBottom), + peak, + peak, + edge, + edge); + } + + if (outerLeft < highlightLeft) + { + drawList.AddRectFilledMultiColor( + new Vector2(outerLeft, highlightTop), + new Vector2(highlightLeft, highlightBottom), + edge, + peak, + peak, + edge); + } + + if (outerRight > highlightRight) + { + drawList.AddRectFilledMultiColor( + new Vector2(highlightRight, highlightTop), + new Vector2(outerRight, highlightBottom), + peak, + edge, + edge, + peak); + } + } + + private static void DrawPointHighlight( + ImDrawListPtr drawList, + Vector2 center, + Vector2 halfSize, + Vector4 edgeColor, + Vector4 peakColor, + bool borderOnly, + float borderThickness) + { + if (halfSize.X <= 0f || halfSize.Y <= 0f) + return; + + if (borderOnly && borderThickness > 0f) + { + DrawPointBorderGlow(drawList, center, halfSize, borderThickness, edgeColor, peakColor); + return; + } + + const int layers = 7; + for (int layer = 0; layer < layers; layer++) + { + float t = layers <= 1 ? 1f : layer / (layers - 1f); + float scale = 1f - 0.75f * t; + var scaledHalfSize = new Vector2(MathF.Max(1f, halfSize.X * scale), MathF.Max(1f, halfSize.Y * scale)); + var color = Vector4.Lerp(edgeColor, peakColor, t); + DrawEllipseFilled(drawList, center, scaledHalfSize, ImGui.ColorConvertFloat4ToU32(color)); + } + } + + private static void DrawPointBorderGlow( + ImDrawListPtr drawList, + Vector2 center, + Vector2 halfSize, + float thickness, + Vector4 edgeColor, + Vector4 peakColor) + { + int layers = Math.Max(6, (int)MathF.Ceiling(thickness)); + for (int i = 0; i < layers; i++) + { + float t = layers <= 1 ? 1f : i / (layers - 1f); + float offset = thickness * t; + var expandedHalfSize = new Vector2(MathF.Max(1f, halfSize.X + offset), MathF.Max(1f, halfSize.Y + offset)); + var color = Vector4.Lerp(peakColor, edgeColor, t); + color.W = Math.Clamp((peakColor.W * 0.8f) + (edgeColor.W - peakColor.W) * t, 0f, 1f); + DrawEllipseStroke(drawList, center, expandedHalfSize, ImGui.ColorConvertFloat4ToU32(color), 2f); + } + } + + private static void DrawEllipseFilled(ImDrawListPtr drawList, Vector2 center, Vector2 halfSize, uint color, int segments = 48) + { + if (halfSize.X <= 0f || halfSize.Y <= 0f) + return; + + BuildEllipsePath(drawList, center, halfSize, segments); + drawList.PathFillConvex(color); + } + + private static void DrawEllipseStroke(ImDrawListPtr drawList, Vector2 center, Vector2 halfSize, uint color, float thickness, int segments = 48) + { + if (halfSize.X <= 0f || halfSize.Y <= 0f) + return; + + BuildEllipsePath(drawList, center, halfSize, segments); + drawList.PathStroke(color, ImDrawFlags.None, MathF.Max(1f, thickness)); + } + + private static void BuildEllipsePath(ImDrawListPtr drawList, Vector2 center, Vector2 halfSize, int segments) + { + const float twoPi = MathF.PI * 2f; + segments = Math.Clamp(segments, 12, 96); + drawList.PathClear(); + for (int i = 0; i < segments; i++) + { + float angle = twoPi * (i / (float)segments); + var point = new Vector2( + center.X + MathF.Cos(angle) * halfSize.X, + center.Y + MathF.Sin(angle) * halfSize.Y); + drawList.PathLineTo(point); + } + } + + private static void DrawRoundedBorderGlow( + ImDrawListPtr drawList, + Vector2 center, + Vector2 halfSize, + float thickness, + Vector4 edgeColor, + Vector4 peakColor, + float rounding) + { + int layers = Math.Max(6, (int)MathF.Ceiling(thickness)); + for (int i = 0; i < layers; i++) + { + float t = layers <= 1 ? 0f : i / (layers - 1f); + float offset = thickness * t; + var min = new Vector2(center.X - halfSize.X - offset, center.Y - halfSize.Y - offset); + var max = new Vector2(center.X + halfSize.X + offset, center.Y + halfSize.Y + offset); + var color = Vector4.Lerp(peakColor, edgeColor, t); + color.W = Math.Clamp((peakColor.W * 0.8f) + (edgeColor.W - peakColor.W) * t, 0f, 1f); + drawList.AddRect(min, max, ImGui.ColorConvertFloat4ToU32(color), MathF.Max(0f, rounding + offset), ImDrawFlags.RoundCornersAll, 2f); + } + } + + private static void DrawHorizontalHighlightRect( + ImDrawListPtr drawList, + float left, + float right, + float top, + float bottom, + Vector4 edgeColor, + Vector4 peakColor, + float midpoint, + float alphaScale) + { + if (right <= left || bottom <= top) + return; + + edgeColor.W *= alphaScale; + peakColor.W *= alphaScale; + + var edge = ImGui.ColorConvertFloat4ToU32(edgeColor); + var peak = ImGui.ColorConvertFloat4ToU32(peakColor); + var highlightMid = top + (bottom - top) * midpoint; + + drawList.AddRectFilledMultiColor( + new Vector2(left, top), + new Vector2(right, highlightMid), + edge, + edge, + peak, + peak); + + drawList.AddRectFilledMultiColor( + new Vector2(left, highlightMid), + new Vector2(right, bottom), + peak, + peak, + edge, + edge); + } + + private static void DrawVerticalHighlightRect( + ImDrawListPtr drawList, + float left, + float right, + float top, + float bottom, + Vector4 edgeColor, + Vector4 peakColor, + float midpoint, + float alphaScale) + { + if (right <= left || bottom <= top) + return; + + edgeColor.W *= alphaScale; + peakColor.W *= alphaScale; + + var edge = ImGui.ColorConvertFloat4ToU32(edgeColor); + var peak = ImGui.ColorConvertFloat4ToU32(peakColor); + var highlightMid = left + (right - left) * midpoint; + + drawList.AddRectFilledMultiColor( + new Vector2(left, top), + new Vector2(highlightMid, bottom), + edge, + peak, + peak, + edge); + + drawList.AddRectFilledMultiColor( + new Vector2(highlightMid, top), + new Vector2(right, bottom), + peak, + edge, + edge, + peak); + } +} diff --git a/LightlessSync/UI/SyncshellAdminUI.cs b/LightlessSync/UI/SyncshellAdminUI.cs index be8e1d4..94d3977 100644 --- a/LightlessSync/UI/SyncshellAdminUI.cs +++ b/LightlessSync/UI/SyncshellAdminUI.cs @@ -2,7 +2,6 @@ using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.ImGuiFileDialog; -using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using LightlessSync.API.Data; @@ -10,14 +9,13 @@ using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto.Group; using LightlessSync.API.Dto.User; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.UI.Handlers; +using LightlessSync.PlayerData.Pairs; using LightlessSync.WebAPI; +using LightlessSync.UI.Services; using Microsoft.Extensions.Logging; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; using System.Globalization; using System.Linq; using System.Numerics; @@ -30,35 +28,28 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase private readonly bool _isModerator = false; private readonly bool _isOwner = false; private readonly List _oneTimeInvites = []; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly LightlessProfileManager _lightlessProfileManager; private readonly FileDialogManager _fileDialogManager; private readonly UiSharedService _uiSharedService; private List _bannedUsers = []; private LightlessGroupProfileData? _profileData = null; - private bool _adjustedForScollBarsLocalProfile = false; - private bool _adjustedForScollBarsOnlineProfile = false; - private string _descriptionText = string.Empty; - private IDalamudTextureWrap? _pfpTextureWrap; private string _profileDescription = string.Empty; - private byte[] _profileImage = []; - private bool _showFileDialogError = false; private int _multiInvites; private string _newPassword; private bool _pwChangeSuccess; private Task? _pruneTestTask; private Task? _pruneTask; private int _pruneDays = 14; - private List _selectedTags = []; public SyncshellAdminUI(ILogger logger, LightlessMediator mediator, ApiController apiController, - UiSharedService uiSharedService, PairManager pairManager, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager, FileDialogManager fileDialogManager) + UiSharedService uiSharedService, PairUiService pairUiService, GroupFullInfoDto groupFullInfo, PerformanceCollectorService performanceCollectorService, LightlessProfileManager lightlessProfileManager, FileDialogManager fileDialogManager) : base(logger, mediator, "Syncshell Admin Panel (" + groupFullInfo.GroupAliasOrGID + ")", performanceCollectorService) { GroupFullInfo = groupFullInfo; _apiController = apiController; _uiSharedService = uiSharedService; - _pairManager = pairManager; + _pairUiService = pairUiService; _lightlessProfileManager = lightlessProfileManager; _fileDialogManager = fileDialogManager; @@ -68,14 +59,6 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase _multiInvites = 30; _pwChangeSuccess = true; IsOpen = true; - Mediator.Subscribe(this, (msg) => - { - if (msg.GroupData == null || string.Equals(msg.GroupData.AliasOrGID, GroupFullInfo.Group.AliasOrGID, StringComparison.Ordinal)) - { - _pfpTextureWrap?.Dispose(); - _pfpTextureWrap = null; - } - }); SizeConstraints = new WindowSizeConstraints() { MinimumSize = new(700, 500), @@ -90,10 +73,13 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase if (!_isModerator && !_isOwner) return; _logger.LogTrace("Drawing Syncshell Admin UI for {group}", GroupFullInfo.GroupAliasOrGID); - GroupFullInfo = _pairManager.Groups[GroupFullInfo.Group]; + var snapshot = _pairUiService.GetSnapshot(); + if (snapshot.GroupsByGid.TryGetValue(GroupFullInfo.Group.GID, out var updatedInfo)) + { + GroupFullInfo = updatedInfo; + } _profileData = _lightlessProfileManager.GetLightlessGroupProfile(GroupFullInfo.Group); - GetTagsFromProfile(); using var id = ImRaii.PushId("syncshell_admin_" + GroupFullInfo.GID); using (_uiSharedService.UidFont.Push()) @@ -215,179 +201,47 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase private void DrawProfile() { var profileTab = ImRaii.TabItem("Profile"); + if (!profileTab) + return; - if (profileTab) + if (_profileData != null) { - if (_uiSharedService.MediumTreeNode("Current Profile", UIColors.Get("LightlessPurple"))) + if (!string.Equals(_profileDescription, _profileData.Description, StringComparison.Ordinal)) { - ImGui.Dummy(new Vector2(5)); - - if (!_profileImage.SequenceEqual(_profileData.ImageData.Value)) - { - _profileImage = _profileData.ImageData.Value; - _pfpTextureWrap?.Dispose(); - _pfpTextureWrap = _uiSharedService.LoadImage(_profileImage); - } - - if (!string.Equals(_profileDescription, _profileData.Description, StringComparison.OrdinalIgnoreCase)) - { - _profileDescription = _profileData.Description; - _descriptionText = _profileDescription; - } - - if (_pfpTextureWrap != null) - { - ImGui.Image(_pfpTextureWrap.Handle, ImGuiHelpers.ScaledVector2(_pfpTextureWrap.Width, _pfpTextureWrap.Height)); - } - - var spacing = ImGui.GetStyle().ItemSpacing.X; - ImGuiHelpers.ScaledRelativeSameLine(256, spacing); - using (_uiSharedService.GameFont.Push()) - { - var descriptionTextSize = ImGui.CalcTextSize(_profileData.Description, wrapWidth: 256f); - var childFrame = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 256); - if (descriptionTextSize.Y > childFrame.Y) - { - _adjustedForScollBarsOnlineProfile = true; - } - else - { - _adjustedForScollBarsOnlineProfile = false; - } - childFrame = childFrame with - { - X = childFrame.X + (_adjustedForScollBarsOnlineProfile ? ImGui.GetStyle().ScrollbarSize : 0), - }; - if (ImGui.BeginChildFrame(101, childFrame)) - { - UiSharedService.TextWrapped(_profileData.Description); - } - ImGui.EndChildFrame(); - ImGui.TreePop(); - } - var nsfw = _profileData.IsNsfw; - ImGui.BeginDisabled(); - ImGui.Checkbox("Is NSFW", ref nsfw); - ImGui.EndDisabled(); + _profileDescription = _profileData.Description; } - ImGui.Separator(); + UiSharedService.TextWrapped("Preview the Syncshell profile in a standalone window."); - if (_uiSharedService.MediumTreeNode("Profile Settings", UIColors.Get("LightlessPurple"))) + if (_uiSharedService.IconTextButton(FontAwesomeIcon.AddressCard, "Open Syncshell Profile")) { - ImGui.Dummy(new Vector2(5)); - ImGui.TextUnformatted($"Profile Picture:"); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.FileUpload, "Upload new profile picture")) - { - _fileDialogManager.OpenFileDialog("Select new Profile picture", ".png", (success, file) => - { - if (!success) return; - _ = Task.Run(async () => - { - var fileContent = await File.ReadAllBytesAsync(file).ConfigureAwait(false); - MemoryStream ms = new(fileContent); - await using (ms.ConfigureAwait(false)) - { - var format = await Image.DetectFormatAsync(ms).ConfigureAwait(false); - if (!format.FileExtensions.Contains("png", StringComparer.OrdinalIgnoreCase)) - { - _showFileDialogError = true; - return; - } - using var image = Image.Load(fileContent); - - if (image.Width > 512 || image.Height > 512 || (fileContent.Length > 2000 * 1024)) - { - _showFileDialogError = true; - return; - } - - _showFileDialogError = false; - await _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: null, Tags: null, Convert.ToBase64String(fileContent), BannerBase64: null, IsNsfw: null, IsDisabled: null)) - .ConfigureAwait(false); - } - }); - }); - } - UiSharedService.AttachToolTip("Select and upload a new profile picture"); - ImGui.SameLine(); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear uploaded profile picture")) - { - _ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: null, Tags: null, PictureBase64: null, BannerBase64: null, IsNsfw: null, IsDisabled: null)); - } - UiSharedService.AttachToolTip("Clear your currently uploaded profile picture"); - if (_showFileDialogError) - { - UiSharedService.ColorTextWrapped("The profile picture must be a PNG file with a maximum height and width of 256px and 250KiB size", ImGuiColors.DalamudRed); - } - ImGui.Separator(); - ImGui.TextUnformatted($"Tags:"); - var childFrameLocal = ImGuiHelpers.ScaledVector2(256 + ImGui.GetStyle().WindowPadding.X + ImGui.GetStyle().WindowBorderSize, 200); - - var allCategoryIndexes = Enum.GetValues() - .Cast() - .ToList(); - - foreach(int tag in allCategoryIndexes) - { - using (ImRaii.PushId($"tag-{tag}")) DrawTag(tag); - } - ImGui.Separator(); - var widthTextBox = 400; - var posX = ImGui.GetCursorPosX(); - ImGui.TextUnformatted($"Description {_descriptionText.Length}/1500"); - ImGui.SetCursorPosX(posX); - ImGuiHelpers.ScaledRelativeSameLine(widthTextBox, ImGui.GetStyle().ItemSpacing.X); - ImGui.TextUnformatted("Preview (approximate)"); - using (_uiSharedService.GameFont.Push()) - ImGui.InputTextMultiline("##description", ref _descriptionText, 1500, ImGuiHelpers.ScaledVector2(widthTextBox, 200)); - - ImGui.SameLine(); - - using (_uiSharedService.GameFont.Push()) - { - var descriptionTextSizeLocal = ImGui.CalcTextSize(_descriptionText, wrapWidth: 256f); - if (descriptionTextSizeLocal.Y > childFrameLocal.Y) - { - _adjustedForScollBarsLocalProfile = true; - } - else - { - _adjustedForScollBarsLocalProfile = false; - } - childFrameLocal = childFrameLocal with - { - X = childFrameLocal.X + (_adjustedForScollBarsLocalProfile ? ImGui.GetStyle().ScrollbarSize : 0), - }; - if (ImGui.BeginChildFrame(102, childFrameLocal)) - { - UiSharedService.TextWrapped(_descriptionText); - } - ImGui.EndChildFrame(); - } - - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Save, "Save Description")) - { - _ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: _descriptionText, Tags: null, PictureBase64: null, BannerBase64: null, IsNsfw: null, IsDisabled: null)); - } - UiSharedService.AttachToolTip("Sets your profile description text"); - ImGui.SameLine(); - if (_uiSharedService.IconTextButton(FontAwesomeIcon.Trash, "Clear Description")) - { - _ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: null, Tags: null, PictureBase64: null, BannerBase64: null, IsNsfw: null, IsDisabled: null)); - } - UiSharedService.AttachToolTip("Clears your profile description text"); - ImGui.Separator(); - ImGui.TextUnformatted($"Profile Options:"); - var isNsfw = _profileData.IsNsfw; - if (ImGui.Checkbox("Profile is NSFW", ref isNsfw)) - { - _ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: null, Tags: null, PictureBase64: null, BannerBase64: null, IsNsfw: isNsfw, IsDisabled: null)); - } - _uiSharedService.DrawHelpText("If your profile description or image can be considered NSFW, toggle this to ON"); - ImGui.TreePop(); + Mediator.Publish(new GroupProfileOpenStandaloneMessage(GroupFullInfo)); } + UiSharedService.AttachToolTip("Opens the standalone Syncshell profile window for this group."); + + ImGuiHelpers.ScaledDummy(2f); + ImGui.TextDisabled("Profile Flags"); + ImGui.BulletText(_profileData.IsNsfw ? "Marked as NSFW" : "Marked as SFW"); + ImGui.BulletText(_profileData.IsDisabled ? "Profile disabled for viewers" : "Profile active"); + + ImGuiHelpers.ScaledDummy(2f); + _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f); + ImGuiHelpers.ScaledDummy(2f); + + UiSharedService.TextWrapped("Open the syncshell profile editor to update images, description, tags, and visibility settings."); + ImGuiHelpers.ScaledDummy(2f); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserEdit, "Open Syncshell Profile Editor")) + { + Mediator.Publish(new OpenGroupProfileEditorMessage(GroupFullInfo)); + } + UiSharedService.AttachToolTip("Launches the editor window and associated live preview for this syncshell."); } + else + { + UiSharedService.TextWrapped("Profile information is loading..."); + } + profileTab.Dispose(); } @@ -398,7 +252,8 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase { if (_uiSharedService.MediumTreeNode("User List & Administration", UIColors.Get("LightlessPurple"))) { - if (!_pairManager.GroupPairs.TryGetValue(GroupFullInfo, out var pairs)) + var snapshot = _pairUiService.GetSnapshot(); + if (!snapshot.GroupPairs.TryGetValue(GroupFullInfo, out var pairs)) { UiSharedService.ColorTextWrapped("No users found in this Syncshell", ImGuiColors.DalamudYellow); } @@ -734,37 +589,8 @@ public class SyncshellAdminUI : WindowMediatorSubscriberBase } inviteTab.Dispose(); } - private void DrawTag(int tag) - { - var HasTag = _selectedTags.Contains(tag); - var tagName = (ProfileTags)tag; - - if (ImGui.Checkbox(tagName.ToString(), ref HasTag)) - { - if (HasTag) - { - _selectedTags.Add(tag); - _ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: null, Tags: _selectedTags.ToArray(), PictureBase64: null, BannerBase64: null, IsNsfw: null, IsDisabled: null)); - } - else - { - _selectedTags.Remove(tag); - _ = _apiController.GroupSetProfile(new GroupProfileDto(new GroupData(GroupFullInfo.Group.AliasOrGID), Description: null, Tags: _selectedTags.ToArray(), PictureBase64: null, BannerBase64: null, IsNsfw: null, IsDisabled: null)); - } - } - } - - private void GetTagsFromProfile() - { - if (_profileData != null) - { - _selectedTags = [.. _profileData.Tags]; - } - } - public override void OnClose() { Mediator.Publish(new RemoveWindowMessage(this)); - _pfpTextureWrap?.Dispose(); } } \ No newline at end of file diff --git a/LightlessSync/UI/SyncshellFinderUI.cs b/LightlessSync/UI/SyncshellFinderUI.cs index d7f5605..823f44a 100644 --- a/LightlessSync/UI/SyncshellFinderUI.cs +++ b/LightlessSync/UI/SyncshellFinderUI.cs @@ -7,13 +7,16 @@ using LightlessSync.API.Data.Enum; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto; using LightlessSync.API.Dto.Group; -using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Utils; using LightlessSync.WebAPI; +using LightlessSync.UI.Services; using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; using System.Numerics; +using System.Threading.Tasks; namespace LightlessSync.UI; @@ -23,7 +26,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase private readonly BroadcastService _broadcastService; private readonly UiSharedService _uiSharedService; private readonly BroadcastScannerService _broadcastScannerService; - private readonly PairManager _pairManager; + private readonly PairUiService _pairUiService; private readonly DalamudUtilService _dalamudUtilService; private readonly List _nearbySyncshells = []; @@ -43,14 +46,14 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase UiSharedService uiShared, ApiController apiController, BroadcastScannerService broadcastScannerService, - PairManager pairManager, + PairUiService pairUiService, DalamudUtilService dalamudUtilService) : base(logger, mediator, "Shellfinder###LightlessSyncshellFinderUI", performanceCollectorService) { _broadcastService = broadcastService; _uiSharedService = uiShared; _apiController = apiController; _broadcastScannerService = broadcastScannerService; - _pairManager = pairManager; + _pairUiService = pairUiService; _dalamudUtilService = dalamudUtilService; IsOpen = false; @@ -266,7 +269,8 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase private async Task RefreshSyncshellsAsync() { var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts(); - _currentSyncshells = [.. _pairManager.GroupPairs.Select(g => g.Key)]; + var snapshot = _pairUiService.GetSnapshot(); + _currentSyncshells = snapshot.GroupPairs.Keys.ToList(); _recentlyJoined.RemoveWhere(gid => _currentSyncshells.Any(s => string.Equals(s.GID, gid, StringComparison.Ordinal))); diff --git a/LightlessSync/UI/Tags/ProfileTagDefinition.cs b/LightlessSync/UI/Tags/ProfileTagDefinition.cs new file mode 100644 index 0000000..fc44aed --- /dev/null +++ b/LightlessSync/UI/Tags/ProfileTagDefinition.cs @@ -0,0 +1,30 @@ +using System.Numerics; + +namespace LightlessSync.UI.Tags; + +public readonly record struct ProfileTagDefinition( + string? Text, + string? SeStringPayload = null, + bool UseTextureSegments = false, + Vector4? BackgroundColor = null, + Vector4? BorderColor = null, + Vector4? TextColor = null) +{ + public bool HasContent => !string.IsNullOrWhiteSpace(Text) || !string.IsNullOrWhiteSpace(SeStringPayload); + public bool HasSeString => !string.IsNullOrWhiteSpace(SeStringPayload); + + public ProfileTagDefinition WithColors(Vector4? background, Vector4? border, Vector4? textColor = null) + => this with { BackgroundColor = background, BorderColor = border, TextColor = textColor }; + + public static ProfileTagDefinition FromText(string text, Vector4? background = null, Vector4? border = null, Vector4? textColor = null) + => new(text, null, false, background, border, textColor); + + public static ProfileTagDefinition FromIcon(uint iconId, Vector4? background = null, Vector4? border = null) + => new(null, $"", true, background, border, null); + + public static ProfileTagDefinition FromIconAndText(uint iconId, string text, Vector4? background = null, Vector4? border = null, Vector4? textColor = null) + => new(text, $" {text}", true, background, border, textColor); + + public static ProfileTagDefinition FromSeString(string payload, Vector4? background = null, Vector4? border = null, Vector4? textColor = null) + => new(null, payload, true, background, border, textColor); +} diff --git a/LightlessSync/UI/Tags/ProfileTagRenderer.cs b/LightlessSync/UI/Tags/ProfileTagRenderer.cs new file mode 100644 index 0000000..67147ee --- /dev/null +++ b/LightlessSync/UI/Tags/ProfileTagRenderer.cs @@ -0,0 +1,226 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Interface.ImGuiSeStringRenderer; +using Dalamud.Interface.Textures.TextureWraps; +using Dalamud.Interface.Utility; +using LightlessSync.Utils; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace LightlessSync.UI.Tags; + +internal static class ProfileTagRenderer +{ + public static Vector2 MeasureTag( + ProfileTagDefinition tag, + float scale, + ImGuiStylePtr style, + Vector4 fallbackBackground, + Vector4 fallbackBorder, + uint defaultTextColorU32, + List segmentBuffer, + Func iconResolver, + ILogger? logger) + => RenderTagInternal(tag, Vector2.Zero, scale, default, style, fallbackBackground, fallbackBorder, defaultTextColorU32, segmentBuffer, iconResolver, logger, draw: false); + + public static Vector2 RenderTag( + ProfileTagDefinition tag, + Vector2 screenMin, + float scale, + ImDrawListPtr drawList, + ImGuiStylePtr style, + Vector4 fallbackBackground, + Vector4 fallbackBorder, + uint defaultTextColorU32, + List segmentBuffer, + Func iconResolver, + ILogger? logger) + => RenderTagInternal(tag, screenMin, scale, drawList, style, fallbackBackground, fallbackBorder, defaultTextColorU32, segmentBuffer, iconResolver, logger, draw: true); + + private static Vector2 RenderTagInternal( + ProfileTagDefinition tag, + Vector2 screenMin, + float scale, + ImDrawListPtr drawList, + ImGuiStylePtr style, + Vector4 fallbackBackground, + Vector4 fallbackBorder, + uint defaultTextColorU32, + List segmentBuffer, + Func iconResolver, + ILogger? logger, + bool draw) + { + segmentBuffer.Clear(); + + var padding = new Vector2(10f * scale, 6f * scale); + var rounding = style.FrameRounding > 0f ? style.FrameRounding : 6f * scale; + + var backgroundColor = tag.BackgroundColor ?? fallbackBackground; + var borderColor = tag.BorderColor ?? fallbackBorder; + var textColor = tag.TextColor ?? style.Colors[(int)ImGuiCol.Text]; + var textColorU32 = tag.TextColor.HasValue ? ImGui.ColorConvertFloat4ToU32(tag.TextColor.Value) : defaultTextColorU32; + + string? textContent = tag.Text; + Vector2 textSize = string.IsNullOrWhiteSpace(textContent) ? Vector2.Zero : ImGui.CalcTextSize(textContent); + + var sePayload = tag.SeStringPayload; + bool hasSeString = !string.IsNullOrWhiteSpace(sePayload); + bool useTextureSegments = hasSeString && tag.UseTextureSegments; + bool useSeRenderer = hasSeString && !useTextureSegments; + Vector2 seSize = Vector2.Zero; + List? seSegments = null; + + if (hasSeString) + { + if (useSeRenderer) + { + try + { + var drawParams = new SeStringDrawParams + { + TargetDrawList = draw ? drawList : default, + ScreenOffset = draw ? screenMin + padding : Vector2.Zero, + WrapWidth = float.MaxValue + }; + + var measure = ImGuiHelpers.CompileSeStringWrapped(sePayload!, drawParams); + seSize = measure.Size; + if (seSize.Y <= 0f) + seSize.Y = ImGui.GetTextLineHeight(); + + textContent = null; + textSize = Vector2.Zero; + } + catch (Exception ex) + { + logger?.LogDebug(ex, "Failed to compile SeString payload '{Payload}' for profile tag", sePayload); + useSeRenderer = false; + } + } + + if (!useSeRenderer && useTextureSegments) + { + segmentBuffer.Clear(); + if (SeStringUtils.TryResolveSegments(sePayload!, scale, iconResolver, segmentBuffer, out seSize) && segmentBuffer.Count > 0) + { + seSegments = segmentBuffer; + textContent = null; + textSize = Vector2.Zero; + } + else + { + segmentBuffer.Clear(); + var fallback = SeStringUtils.StripMarkup(sePayload!); + if (!string.IsNullOrWhiteSpace(fallback)) + { + textContent = fallback; + textSize = ImGui.CalcTextSize(fallback); + } + } + } + else if (!useSeRenderer && string.IsNullOrWhiteSpace(textContent)) + { + var fallback = SeStringUtils.StripMarkup(sePayload!); + if (!string.IsNullOrWhiteSpace(fallback)) + { + textContent = fallback; + textSize = ImGui.CalcTextSize(fallback); + } + } + } + + bool drewSeString = useSeRenderer || seSegments is { Count: > 0 }; + var contentHeight = drewSeString ? seSize.Y : textSize.Y; + if (contentHeight <= 0f) + contentHeight = ImGui.GetTextLineHeight(); + + var contentWidth = drewSeString ? seSize.X : textSize.X; + if (contentWidth <= 0f) + contentWidth = textSize.X; + if (contentWidth <= 0f) + contentWidth = 40f * scale; + + var tagSize = new Vector2(contentWidth + padding.X * 2f, contentHeight + padding.Y * 2f); + + if (!draw) + { + if (seSegments is not null) + seSegments.Clear(); + return tagSize; + } + + var rectMin = screenMin; + var rectMax = rectMin + tagSize; + drawList.AddRectFilled(rectMin, rectMax, ImGui.ColorConvertFloat4ToU32(backgroundColor), rounding); + drawList.AddRect(rectMin, rectMax, ImGui.ColorConvertFloat4ToU32(borderColor), rounding); + + var contentStart = rectMin + padding; + var verticalOffset = (tagSize.Y - padding.Y * 2f - contentHeight) * 0.5f; + var basePos = new Vector2(contentStart.X, contentStart.Y + MathF.Max(verticalOffset, 0f)); + + if (useSeRenderer && sePayload is { Length: > 0 }) + { + var drawParams = new SeStringDrawParams + { + TargetDrawList = drawList, + ScreenOffset = basePos, + WrapWidth = float.MaxValue + }; + + try + { + ImGuiHelpers.CompileSeStringWrapped(sePayload!, drawParams); + } + catch (Exception ex) + { + logger?.LogDebug(ex, "Failed to draw SeString payload '{Payload}' for profile tag", sePayload); + var fallback = !string.IsNullOrWhiteSpace(textContent) ? textContent : SeStringUtils.StripMarkup(sePayload!); + if (!string.IsNullOrWhiteSpace(fallback)) + drawList.AddText(basePos, textColorU32, fallback); + } + } + else if (seSegments is { Count: > 0 }) + { + var segmentX = basePos.X; + foreach (var segment in seSegments) + { + var segmentPos = new Vector2(segmentX, basePos.Y + (contentHeight - segment.Size.Y) * 0.5f); + switch (segment.Type) + { + case SeStringUtils.SeStringSegmentType.Icon: + if (segment.Texture != null) + { + drawList.AddImage(segment.Texture.Handle, segmentPos, segmentPos + segment.Size); + } + else if (!string.IsNullOrEmpty(segment.Text)) + { + drawList.AddText(segmentPos, textColorU32, segment.Text); + } + break; + case SeStringUtils.SeStringSegmentType.Text: + var colorU32 = segment.Color.HasValue + ? ImGui.ColorConvertFloat4ToU32(segment.Color.Value) + : textColorU32; + drawList.AddText(segmentPos, colorU32, segment.Text ?? string.Empty); + break; + } + + segmentX += segment.Size.X; + } + + seSegments.Clear(); + } + else if (!string.IsNullOrWhiteSpace(textContent)) + { + drawList.AddText(basePos, textColorU32, textContent); + } + else + { + drawList.AddText(basePos, textColorU32, string.Empty); + } + + return tagSize; + } +} diff --git a/LightlessSync/UI/Tags/ProfileTagService.cs b/LightlessSync/UI/Tags/ProfileTagService.cs new file mode 100644 index 0000000..14b1a45 --- /dev/null +++ b/LightlessSync/UI/Tags/ProfileTagService.cs @@ -0,0 +1,131 @@ +using LightlessSync.UI; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace LightlessSync.UI.Tags; + +/// +/// Library of tags. That's it. +/// +public sealed class ProfileTagService +{ + private static readonly IReadOnlyDictionary TagLibrary = CreateTagLibrary(); + + public IReadOnlyDictionary GetTagLibrary() + => TagLibrary; + + public IReadOnlyList ResolveTags(IReadOnlyList? tagIds) + { + if (tagIds is null || tagIds.Count == 0) + return Array.Empty(); + + var result = new List(tagIds.Count); + foreach (var id in tagIds) + { + if (TagLibrary.TryGetValue(id, out var tag)) + result.Add(tag); + } + + return result; + } + + public bool TryGetDefinition(int tagId, out ProfileTagDefinition definition) + => TagLibrary.TryGetValue(tagId, out definition); + + private static IReadOnlyDictionary CreateTagLibrary() + { + var dictionary = new Dictionary + { + [(int)ProfileTags.SFW] = ProfileTagDefinition.FromIconAndText( + 230419, + "SFW", + background: new Vector4(0.16f, 0.24f, 0.18f, 0.95f), + border: new Vector4(0.32f, 0.52f, 0.34f, 0.85f), + textColor: new Vector4(0.78f, 0.94f, 0.80f, 1f)), + + [(int)ProfileTags.NSFW] = ProfileTagDefinition.FromIconAndText( + 230419, + "NSFW", + background: new Vector4(0.32f, 0.18f, 0.22f, 0.95f), + border: new Vector4(0.72f, 0.32f, 0.38f, 0.85f), + textColor: new Vector4(1f, 0.82f, 0.86f, 1f)), + + + [(int)ProfileTags.RP] = ProfileTagDefinition.FromIconAndText( + 61545, + "RP", + background: new Vector4(0.20f, 0.20f, 0.30f, 0.95f), + border: new Vector4(0.42f, 0.42f, 0.66f, 0.85f), + textColor: new Vector4(0.80f, 0.84f, 1f, 1f)), + + [(int)ProfileTags.ERP] = ProfileTagDefinition.FromIconAndText( + 61545, + "ERP", + background: new Vector4(0.20f, 0.20f, 0.30f, 0.95f), + border: new Vector4(0.42f, 0.42f, 0.66f, 0.85f), + textColor: new Vector4(0.80f, 0.84f, 1f, 1f)), + + [(int)ProfileTags.No_RP] = ProfileTagDefinition.FromIconAndText( + 230420, + "No RP", + background: new Vector4(0.30f, 0.18f, 0.30f, 0.95f), + border: new Vector4(0.69f, 0.40f, 0.65f, 0.85f), + textColor: new Vector4(1f, 0.84f, 1f, 1f)), + + [(int)ProfileTags.No_ERP] = ProfileTagDefinition.FromIconAndText( + 230420, + "No ERP", + background: new Vector4(0.30f, 0.18f, 0.30f, 0.95f), + border: new Vector4(0.69f, 0.40f, 0.65f, 0.85f), + textColor: new Vector4(1f, 0.84f, 1f, 1f)), + + + [(int)ProfileTags.Venues] = ProfileTagDefinition.FromIconAndText( + 60756, + "Venues", + background: new Vector4(0.18f, 0.24f, 0.28f, 0.95f), + border: new Vector4(0.33f, 0.55f, 0.63f, 0.85f), + textColor: new Vector4(0.78f, 0.90f, 0.97f, 1f)), + + [(int)ProfileTags.Gpose] = ProfileTagDefinition.FromIconAndText( + 61546, + "GPose", + background: new Vector4(0.18f, 0.18f, 0.26f, 0.95f), + border: new Vector4(0.35f, 0.34f, 0.54f, 0.85f), + textColor: new Vector4(0.80f, 0.82f, 0.96f, 1f)), + + + [(int)ProfileTags.Limsa] = ProfileTagDefinition.FromIconAndText( + 60572, + "Limsa"), + + [(int)ProfileTags.Gridania] = ProfileTagDefinition.FromIconAndText( + 60573, + "Gridania"), + + [(int)ProfileTags.Ul_dah] = ProfileTagDefinition.FromIconAndText( + 60574, + "Ul'dah"), + + + [(int)ProfileTags.WUT] = ProfileTagDefinition.FromIconAndText( + 61397, + "WU/T"), + + + [(int)ProfileTags.PVP] = ProfileTagDefinition.FromIcon(61806), + [(int)ProfileTags.Ultimate] = ProfileTagDefinition.FromIcon(61832), + [(int)ProfileTags.Raids] = ProfileTagDefinition.FromIcon(61802), + [(int)ProfileTags.Roulette] = ProfileTagDefinition.FromIcon(61807), + [(int)ProfileTags.Crafting] = ProfileTagDefinition.FromIcon(61816), + [(int)ProfileTags.Casual] = ProfileTagDefinition.FromIcon(61753), + [(int)ProfileTags.Hardcore] = ProfileTagDefinition.FromIcon(61754), + [(int)ProfileTags.Glamour] = ProfileTagDefinition.FromIcon(61759), + [(int)ProfileTags.Mentor] = ProfileTagDefinition.FromIcon(61760) + + }; + + return dictionary; + } +} diff --git a/LightlessSync/UI/TopTabMenu.cs b/LightlessSync/UI/TopTabMenu.cs index b4327c0..cd24118 100644 --- a/LightlessSync/UI/TopTabMenu.cs +++ b/LightlessSync/UI/TopTabMenu.cs @@ -1,3 +1,4 @@ +using System; using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Utility; @@ -10,8 +11,12 @@ using LightlessSync.PlayerData.Pairs; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Utils; +using LightlessSync.UI.Models; +using LightlessSync.UI.Style; using LightlessSync.WebAPI; using System.Numerics; +using System.Threading.Tasks; +using System.Linq; namespace LightlessSync.UI; @@ -22,7 +27,6 @@ public class TopTabMenu private readonly LightlessMediator _lightlessMediator; - private readonly PairManager _pairManager; private readonly PairRequestService _pairRequestService; private readonly DalamudUtilService _dalamudUtilService; private readonly HashSet _pendingPairRequestActions = new(StringComparer.Ordinal); @@ -36,11 +40,12 @@ public class TopTabMenu private string _pairToAdd = string.Empty; private SelectedTab _selectedTab = SelectedTab.None; - public TopTabMenu(LightlessMediator lightlessMediator, ApiController apiController, PairManager pairManager, UiSharedService uiSharedService, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, NotificationService lightlessNotificationService) + private PairUiSnapshot? _currentSnapshot; + + public TopTabMenu(LightlessMediator lightlessMediator, ApiController apiController, UiSharedService uiSharedService, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, NotificationService lightlessNotificationService) { _lightlessMediator = lightlessMediator; _apiController = apiController; - _pairManager = pairManager; _pairRequestService = pairRequestService; _dalamudUtilService = dalamudUtilService; _uiSharedService = uiSharedService; @@ -77,34 +82,46 @@ public class TopTabMenu _selectedTab = value; } } - public void Draw() + + private PairUiSnapshot Snapshot => _currentSnapshot ?? throw new InvalidOperationException("Pair UI snapshot is not available outside of Draw."); + + public void Draw(PairUiSnapshot snapshot) { - var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; - var spacing = ImGui.GetStyle().ItemSpacing; - var buttonX = (availableWidth - (spacing.X * 4)) / 5f; - var buttonY = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause).Y; - var buttonSize = new Vector2(buttonX, buttonY); - var drawList = ImGui.GetWindowDrawList(); - var underlineColor = ImGui.GetColorU32(UIColors.Get("LightlessPurpleActive")); // ImGui.GetColorU32(ImGuiCol.Separator); - var btncolor = ImRaii.PushColor(ImGuiCol.Button, ImGui.ColorConvertFloat4ToU32(new(0, 0, 0, 0))); - - ImGuiHelpers.ScaledDummy(spacing.Y / 2f); - - using (ImRaii.PushFont(UiBuilder.IconFont)) + _currentSnapshot = snapshot; + try { - var x = ImGui.GetCursorScreenPos(); - if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), buttonSize)) + var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; + var spacing = ImGui.GetStyle().ItemSpacing; + var buttonX = (availableWidth - (spacing.X * 5)) / 6f; + var buttonY = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause).Y; + var buttonSize = new Vector2(buttonX, buttonY); + const float buttonBorderThickness = 12f; + var buttonRounding = ImGui.GetStyle().FrameRounding; + var drawList = ImGui.GetWindowDrawList(); + var underlineColor = ImGui.GetColorU32(UIColors.Get("LightlessPurpleActive")); // ImGui.GetColorU32(ImGuiCol.Separator); + var btncolor = ImRaii.PushColor(ImGuiCol.Button, ImGui.ColorConvertFloat4ToU32(new(0, 0, 0, 0))); + + ImGuiHelpers.ScaledDummy(spacing.Y / 2f); + + using (ImRaii.PushFont(UiBuilder.IconFont)) { - TabSelection = TabSelection == SelectedTab.Individual ? SelectedTab.None : SelectedTab.Individual; + var x = ImGui.GetCursorScreenPos(); + if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), buttonSize)) + { + TabSelection = TabSelection == SelectedTab.Individual ? SelectedTab.None : SelectedTab.Individual; + } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding); + } + ImGui.SameLine(); + var xAfter = ImGui.GetCursorScreenPos(); + if (TabSelection == SelectedTab.Individual) + drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, + xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, + underlineColor, 2); } - ImGui.SameLine(); - var xAfter = ImGui.GetCursorScreenPos(); - if (TabSelection == SelectedTab.Individual) - drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, - xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, - underlineColor, 2); - } - UiSharedService.AttachToolTip("Individual Pair Menu"); + UiSharedService.AttachToolTip("Individual Pair Menu"); using (ImRaii.PushFont(UiBuilder.IconFont)) { @@ -113,6 +130,10 @@ public class TopTabMenu { TabSelection = TabSelection == SelectedTab.Syncshell ? SelectedTab.None : SelectedTab.Syncshell; } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding); + } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); if (TabSelection == SelectedTab.Syncshell) @@ -122,6 +143,20 @@ public class TopTabMenu } UiSharedService.AttachToolTip("Syncshell Menu"); + using (ImRaii.PushFont(UiBuilder.IconFont)) + { + if (ImGui.Button(FontAwesomeIcon.Comments.ToIconString(), buttonSize)) + { + _lightlessMediator.Publish(new UiToggleMessage(typeof(ZoneChatUi))); + } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding); + } + } + UiSharedService.AttachToolTip("Zone Chat"); + ImGui.SameLine(); + ImGui.SameLine(); using (ImRaii.PushFont(UiBuilder.IconFont)) { @@ -130,6 +165,10 @@ public class TopTabMenu { TabSelection = TabSelection == SelectedTab.Lightfinder ? SelectedTab.None : SelectedTab.Lightfinder; } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding); + } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); @@ -148,6 +187,10 @@ public class TopTabMenu { TabSelection = TabSelection == SelectedTab.UserConfig ? SelectedTab.None : SelectedTab.UserConfig; } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding); + } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); @@ -166,6 +209,10 @@ public class TopTabMenu { _lightlessMediator.Publish(new UiToggleMessage(typeof(SettingsUi))); } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding); + } ImGui.SameLine(); } UiSharedService.AttachToolTip("Open Lightless Settings"); @@ -196,12 +243,18 @@ public class TopTabMenu if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f); + DrawIncomingPairRequests(availableWidth); ImGui.Separator(); DrawFilter(availableWidth, spacing.X); } + finally + { + _currentSnapshot = null; + } + } private void DrawAddPair(float availableXWidth, float spacingX) { @@ -209,7 +262,7 @@ public class TopTabMenu ImGui.SetNextItemWidth(availableXWidth - buttonSize - spacingX); ImGui.InputTextWithHint("##otheruid", "Other players UID/Alias", ref _pairToAdd, 20); ImGui.SameLine(); - var alreadyExisting = _pairManager.DirectPairs.Exists(p => string.Equals(p.UserData.UID, _pairToAdd, StringComparison.Ordinal) || string.Equals(p.UserData.Alias, _pairToAdd, StringComparison.Ordinal)); + var alreadyExisting = Snapshot.DirectPairs.Any(p => string.Equals(p.UserData.UID, _pairToAdd, StringComparison.Ordinal) || string.Equals(p.UserData.Alias, _pairToAdd, StringComparison.Ordinal)); using (ImRaii.Disabled(alreadyExisting || string.IsNullOrEmpty(_pairToAdd))) { if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, "Add")) @@ -431,12 +484,23 @@ public class TopTabMenu { Filter = filter; } + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, 10, exactSize: true, clipToElement: true, roundingOverride: ImGui.GetStyle().FrameRounding); + } ImGui.SameLine(); - using var disabled = ImRaii.Disabled(string.IsNullOrEmpty(Filter)); + var disableClear = string.IsNullOrEmpty(Filter); + using var disabled = ImRaii.Disabled(disableClear); + var clearHovered = false; if (_uiSharedService.IconTextButton(FontAwesomeIcon.Ban, "Clear")) { Filter = string.Empty; } + clearHovered = ImGui.IsItemHovered(); + if (!disableClear && clearHovered) + { + Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, 10, exactSize: true, clipToElement: true, roundingOverride: ImGui.GetStyle().FrameRounding); + } } private void DrawGlobalIndividualButtons(float availableXWidth, float spacingX) @@ -666,7 +730,7 @@ public class TopTabMenu if (ImGui.Button(FontAwesomeIcon.Check.ToIconString(), buttonSize)) { _ = GlobalControlCountdown(10); - var bulkSyncshells = _pairManager.GroupPairs.Keys.OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase) + var bulkSyncshells = Snapshot.GroupPairs.Keys.OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Group.GID, g => { var perm = g.GroupUserPermissions; @@ -691,7 +755,8 @@ public class TopTabMenu { var buttonX = (availableWidth - (spacingX)) / 2f; - using (ImRaii.Disabled(_pairManager.GroupPairs.Select(k => k.Key).Distinct() + using (ImRaii.Disabled(Snapshot.GroupPairs.Keys + .Distinct() .Count(g => string.Equals(g.OwnerUID, _apiController.UID, StringComparison.Ordinal)) >= _apiController.ServerInfo.MaxGroupsCreatedByUser)) { if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Create new Syncshell", buttonX)) @@ -701,7 +766,7 @@ public class TopTabMenu ImGui.SameLine(); } - using (ImRaii.Disabled(_pairManager.GroupPairs.Select(k => k.Key).Distinct().Count() >= _apiController.ServerInfo.MaxGroupsJoinedByUser)) + using (ImRaii.Disabled(Snapshot.GroupPairs.Keys.Distinct().Count() >= _apiController.ServerInfo.MaxGroupsJoinedByUser)) { if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Join existing Syncshell", buttonX)) { @@ -770,7 +835,7 @@ public class TopTabMenu if (_uiSharedService.IconTextButton(enableIcon, enableText, null, true)) { _ = GlobalControlCountdown(10); - var bulkIndividualPairs = _pairManager.PairsWithGroups.Keys + var bulkIndividualPairs = Snapshot.PairsWithGroups.Keys .Where(g => g.IndividualPairStatus == IndividualPairStatus.Bidirectional) .ToDictionary(g => g.UserPair.User.UID, g => { @@ -784,7 +849,7 @@ public class TopTabMenu if (_uiSharedService.IconTextButton(disableIcon, disableText, null, true)) { _ = GlobalControlCountdown(10); - var bulkIndividualPairs = _pairManager.PairsWithGroups.Keys + var bulkIndividualPairs = Snapshot.PairsWithGroups.Keys .Where(g => g.IndividualPairStatus == IndividualPairStatus.Bidirectional) .ToDictionary(g => g.UserPair.User.UID, g => { @@ -808,7 +873,7 @@ public class TopTabMenu if (_uiSharedService.IconTextButton(enableIcon, enableText, null, true)) { _ = GlobalControlCountdown(10); - var bulkSyncshells = _pairManager.GroupPairs.Keys + var bulkSyncshells = Snapshot.GroupPairs.Keys .OrderBy(u => u.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Group.GID, g => { @@ -822,7 +887,7 @@ public class TopTabMenu if (_uiSharedService.IconTextButton(disableIcon, disableText, null, true)) { _ = GlobalControlCountdown(10); - var bulkSyncshells = _pairManager.GroupPairs.Keys + var bulkSyncshells = Snapshot.GroupPairs.Keys .OrderBy(u => u.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase) .ToDictionary(g => g.Group.GID, g => { diff --git a/LightlessSync/UI/UIColors.cs b/LightlessSync/UI/UIColors.cs index 3c1eabd..98551f3 100644 --- a/LightlessSync/UI/UIColors.cs +++ b/LightlessSync/UI/UIColors.cs @@ -15,7 +15,9 @@ namespace LightlessSync.UI { "FullBlack", "#000000" }, { "LightlessBlue", "#a6c2ff" }, { "LightlessYellow", "#ffe97a" }, + { "LightlessYellow2", "#cfbd63" }, { "LightlessGreen", "#7cd68a" }, + { "LightlessGreenDefault", "#468a50" }, { "LightlessOrange", "#ffb366" }, { "PairBlue", "#88a2db" }, { "DimRed", "#d44444" }, @@ -25,6 +27,9 @@ namespace LightlessSync.UI { "Lightfinder", "#ad8af5" }, { "LightfinderEdge", "#000000" }, + + { "ProfileBodyGradientTop", "#2f283fff" }, + { "ProfileBodyGradientBottom", "#372d4d00" }, }; private static LightlessConfigService? _configService; diff --git a/LightlessSync/UI/UISharedService.cs b/LightlessSync/UI/UISharedService.cs index eb3acce..1d1c6b0 100644 --- a/LightlessSync/UI/UISharedService.cs +++ b/LightlessSync/UI/UISharedService.cs @@ -4,6 +4,7 @@ using Dalamud.Interface.Colors; using Dalamud.Interface.GameFonts; using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.ManagedFontAtlas; +using Dalamud.Interface.Textures; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; @@ -400,10 +401,21 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase public static bool ShiftPressed() => (GetKeyState(0xA1) & 0x8000) != 0 || (GetKeyState(0xA0) & 0x8000) != 0; - public static void TextWrapped(string text, float wrapPos = 0) + public static void TextWrapped(string text, float wrapPos = 0, Vector4? color = null) { ImGui.PushTextWrapPos(wrapPos); + if (color.HasValue) + { + ImGui.PushStyleColor(ImGuiCol.Text, color.Value); + } + ImGui.TextUnformatted(text); + + if (color.HasValue) + { + ImGui.PopStyleColor(); + } + ImGui.PopTextWrapPos(); } @@ -519,8 +531,9 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase bool changed = ImGui.Checkbox(label, ref value); + var boxSize = ImGui.GetFrameHeight(); var min = pos; - var max = ImGui.GetItemRectMax(); + var max = new Vector2(pos.X + boxSize, pos.Y + boxSize); var col = ImGui.GetColorU32(borderColor ?? ImGuiColors.DalamudGrey); ImGui.GetWindowDrawList().AddRect(min, max, col, rounding, ImDrawFlags.None, borderThickness); @@ -1220,6 +1233,100 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase return _textureProvider.CreateFromImageAsync(imageData).Result; } + private static readonly (bool ItemHq, bool HiRes)[] IconLookupOrders = + [ + (false, true), + (true, true), + (false, false), + (true, false) + ]; + + public bool TryGetIcon(uint iconId, out IDalamudTextureWrap? wrap) + { + foreach (var (itemHq, hiRes) in IconLookupOrders) + { + if (TryGetIconWithLookup(iconId, itemHq, hiRes, out wrap)) + return true; + } + + foreach (var (itemHq, hiRes) in IconLookupOrders) + { + if (!_textureProvider.TryGetIconPath(new GameIconLookup(iconId, itemHq, hiRes), out var path) || string.IsNullOrEmpty(path)) + continue; + + try + { + var reference = _textureProvider.GetFromGame(path); + if (reference.TryGetWrap(out var texture, out _)) + { + wrap = texture; + return true; + } + } + catch (Exception ex) + { + Logger.LogTrace(ex, "Failed to load icon {IconId} from path {Path}", iconId, path); + } + } + + foreach (var hiRes in new[] { true, false }) + { + var manualPath = BuildIconPath(iconId, hiRes); + if (TryLoadTextureFromPath(manualPath, iconId, out wrap)) + return true; + } + + wrap = null; + return false; + } + + private bool TryLoadTextureFromPath(string path, uint iconId, out IDalamudTextureWrap? wrap) + { + try + { + var reference = _textureProvider.GetFromGame(path); + if (reference.TryGetWrap(out var texture, out _)) + { + wrap = texture; + return true; + } + } + catch (Exception ex) + { + Logger.LogTrace(ex, "Failed to load icon {IconId} from manual path {Path}", iconId, path); + } + + wrap = null; + return false; + } + + private static string BuildIconPath(uint iconId, bool hiRes) + { + var folder = iconId - iconId % 1000; + var basePath = $"ui/icon/{folder:000000}/{iconId:000000}"; + return hiRes ? $"{basePath}_hr1.tex" : $"{basePath}.tex"; + } + + private bool TryGetIconWithLookup(uint iconId, bool itemHq, bool hiRes, out IDalamudTextureWrap? wrap) + { + try + { + var icon = _textureProvider.GetFromGameIcon(new GameIconLookup(iconId, itemHq, hiRes)); + if (icon.TryGetWrap(out var texture, out _)) + { + wrap = texture; + return true; + } + } + catch (Exception ex) + { + Logger.LogTrace(ex, "Failed to load icon {IconId} (HQ:{ItemHq}, HR:{HiRes})", iconId, itemHq, hiRes); + } + + wrap = null; + return false; + } + public void LoadLocalization(string languageCode) { _localization.SetupWithLangCode(languageCode); @@ -1285,13 +1392,24 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase num++; } - ImGui.PushID(text); + string displayText = text; + string idText = text; + int idSeparatorIndex = text.IndexOf("##", StringComparison.Ordinal); + if (idSeparatorIndex >= 0) + { + displayText = text[..idSeparatorIndex]; + idText = text[(idSeparatorIndex + 2)..]; + if (string.IsNullOrEmpty(idText)) + idText = displayText; + } + + ImGui.PushID(idText); Vector2 vector; using (IconFont.Push()) vector = ImGui.CalcTextSize(icon.ToIconString()); - Vector2 vector2 = ImGui.CalcTextSize(text); + Vector2 vector2 = ImGui.CalcTextSize(displayText); ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList(); Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); float num2 = 3f * ImGuiHelpers.GlobalScale; @@ -1316,7 +1434,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase windowDrawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString()); Vector2 pos2 = new Vector2(pos.X + vector.X + num2, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); - windowDrawList.AddText(pos2, ImGui.GetColorU32(ImGuiCol.Text), text); + windowDrawList.AddText(pos2, ImGui.GetColorU32(ImGuiCol.Text), displayText); ImGui.PopID(); if (num > 0) { diff --git a/LightlessSync/UI/ZoneChatUi.cs b/LightlessSync/UI/ZoneChatUi.cs new file mode 100644 index 0000000..d8ac877 --- /dev/null +++ b/LightlessSync/UI/ZoneChatUi.cs @@ -0,0 +1,1101 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; +using LightlessSync.API.Data; +using Dalamud.Bindings.ImGui; +using Dalamud.Interface; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using LightlessSync.API.Dto.Chat; +using LightlessSync.LightlessConfiguration; +using LightlessSync.LightlessConfiguration.Models; +using LightlessSync.PlayerData.Pairs; +using LightlessSync.Services; +using LightlessSync.Services.Chat; +using LightlessSync.Services.Mediator; +using LightlessSync.UI.Services; +using LightlessSync.Utils; +using LightlessSync.WebAPI; +using LightlessSync.WebAPI.SignalR.Utils; +using Microsoft.Extensions.Logging; + +namespace LightlessSync.UI; + +public sealed class ZoneChatUi : WindowMediatorSubscriberBase +{ + private const string ChatDisabledStatus = "Chat services disabled"; + private const string SettingsPopupId = "zone_chat_settings_popup"; + private const float DefaultWindowOpacity = .97f; + private const float MinWindowOpacity = 0.05f; + private const float MaxWindowOpacity = 1f; + + private readonly UiSharedService _uiSharedService; + private readonly ZoneChatService _zoneChatService; + private readonly PairUiService _pairUiService; + private readonly LightlessProfileManager _profileManager; + private readonly ApiController _apiController; + private readonly ChatConfigService _chatConfigService; + private readonly Dictionary _draftMessages = new(StringComparer.Ordinal); + private readonly ImGuiWindowFlags _unpinnedWindowFlags; + private float _currentWindowOpacity = DefaultWindowOpacity; + private bool _isWindowPinned; + private bool _showRulesOverlay = true; + + private string? _selectedChannelKey; + private bool _scrollToBottom = true; + private float? _pendingChannelScroll; + private float _channelScroll; + private float _channelScrollMax; + + public ZoneChatUi( + ILogger logger, + LightlessMediator mediator, + UiSharedService uiSharedService, + ZoneChatService zoneChatService, + PairUiService pairUiService, + LightlessProfileManager profileManager, + ChatConfigService chatConfigService, + ApiController apiController, + PerformanceCollectorService performanceCollectorService) + : base(logger, mediator, "Zone Chat", performanceCollectorService) + { + _uiSharedService = uiSharedService; + _zoneChatService = zoneChatService; + _pairUiService = pairUiService; + _profileManager = profileManager; + _chatConfigService = chatConfigService; + _apiController = apiController; + _isWindowPinned = _chatConfigService.Current.IsWindowPinned; + _showRulesOverlay = _chatConfigService.Current.ShowRulesOverlayOnOpen; + if (_chatConfigService.Current.AutoOpenChatOnPluginLoad) + { + IsOpen = true; + } + _unpinnedWindowFlags = Flags; + RefreshWindowFlags(); + Size = new Vector2(450, 420) * ImGuiHelpers.GlobalScale; + SizeCondition = ImGuiCond.FirstUseEver; + SizeConstraints = new() + { + MinimumSize = new Vector2(320f, 260f) * ImGuiHelpers.GlobalScale, + MaximumSize = new Vector2(900f, 900f) * ImGuiHelpers.GlobalScale + }; + + Mediator.Subscribe(this, OnChatChannelMessageAdded); + Mediator.Subscribe(this, msg => + { + if (_selectedChannelKey is not null && string.Equals(_selectedChannelKey, msg.ChannelKey, StringComparison.Ordinal)) + { + _scrollToBottom = true; + } + }); + Mediator.Subscribe(this, _ => _scrollToBottom = true); + } + + public override void PreDraw() + { + RefreshWindowFlags(); + base.PreDraw(); + _currentWindowOpacity = Math.Clamp(_chatConfigService.Current.ChatWindowOpacity, MinWindowOpacity, MaxWindowOpacity); + ImGui.SetNextWindowBgAlpha(_currentWindowOpacity); + } + + protected override void DrawInternal() + { + var childBgColor = ImGui.GetStyle().Colors[(int)ImGuiCol.ChildBg]; + childBgColor.W *= _currentWindowOpacity; + using var childBg = ImRaii.PushColor(ImGuiCol.ChildBg, childBgColor); + DrawConnectionControls(); + + var channels = _zoneChatService.GetChannelsSnapshot(); + + if (channels.Count == 0) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3); + ImGui.TextWrapped("No chat channels available."); + ImGui.PopStyleColor(); + return; + } + + EnsureSelectedChannel(channels); + CleanupDrafts(channels); + + DrawChannelButtons(channels); + + if (_selectedChannelKey is null) + return; + + var activeChannel = channels.FirstOrDefault(channel => string.Equals(channel.Key, _selectedChannelKey, StringComparison.Ordinal)); + if (activeChannel.Equals(default(ChatChannelSnapshot))) + { + activeChannel = channels[0]; + _selectedChannelKey = activeChannel.Key; + } + + _zoneChatService.SetActiveChannel(activeChannel.Key); + + DrawHeader(activeChannel); + ImGui.Separator(); + DrawMessageArea(activeChannel, _currentWindowOpacity); + ImGui.Separator(); + DrawInput(activeChannel); + + if (_showRulesOverlay) + { + DrawRulesOverlay(); + } + } + + private void DrawHeader(ChatChannelSnapshot channel) + { + var prefix = channel.Type == ChatChannelType.Zone ? "Zone" : "Syncshell"; + Vector4 color; + + if (!channel.IsConnected) + { + color = UIColors.Get("DimRed"); + } + else if (!channel.IsAvailable) + { + color = ImGuiColors.DalamudGrey3; + } + else + { + color = channel.Type == ChatChannelType.Zone ? UIColors.Get("LightlessPurple") : UIColors.Get("LightlessBlue"); + } + + ImGui.TextColored(color, $"{prefix}: {channel.DisplayName}"); + + if (channel.Type == ChatChannelType.Zone && channel.Descriptor.WorldId != 0) + { + ImGui.SameLine(); + ImGui.TextUnformatted($"World #{channel.Descriptor.WorldId}"); + } + + var showInlineDisabled = string.Equals(channel.StatusText, ChatDisabledStatus, StringComparison.OrdinalIgnoreCase); + if (showInlineDisabled) + { + ImGui.SameLine(); + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3); + ImGui.TextUnformatted($"| {channel.StatusText}"); + ImGui.PopStyleColor(); + } + else if (!string.IsNullOrEmpty(channel.StatusText)) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3); + ImGui.TextWrapped(channel.StatusText); + ImGui.PopStyleColor(); + } + } + + private void DrawMessageArea(ChatChannelSnapshot channel, float windowOpacity) + { + var available = ImGui.GetContentRegionAvail(); + var inputHeight = ImGui.GetFrameHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y; + var height = Math.Max(100f * ImGuiHelpers.GlobalScale, available.Y - inputHeight); + + using var child = ImRaii.Child($"chat_messages_{channel.Key}", new Vector2(-1, height), false); + if (!child) + return; + + var drawList = ImGui.GetWindowDrawList(); + var windowPos = ImGui.GetWindowPos(); + var windowSize = ImGui.GetWindowSize(); + var gradientBottom = UIColors.Get("LightlessPurple"); + var bottomAlpha = 0.12f * windowOpacity; + var bottomColorVec = new Vector4(gradientBottom.X, gradientBottom.Y, gradientBottom.Z, bottomAlpha); + var topColorVec = new Vector4(gradientBottom.X, gradientBottom.Y, gradientBottom.Z, 0.0f); + var bottomColor = ImGui.ColorConvertFloat4ToU32(bottomColorVec); + var topColor = ImGui.ColorConvertFloat4ToU32(topColorVec); + drawList.AddRectFilledMultiColor( + windowPos, + windowPos + windowSize, + topColor, + topColor, + bottomColor, + bottomColor); + + var showTimestamps = _chatConfigService.Current.ShowMessageTimestamps; + + if (channel.Messages.Count == 0) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3); + ImGui.TextWrapped("Chat history will appear here when available."); + ImGui.PopStyleColor(); + } + else + { + for (var i = 0; i < channel.Messages.Count; i++) + { + var message = channel.Messages[i]; + var timestampText = string.Empty; + if (showTimestamps) + { + timestampText = $"[{message.ReceivedAtUtc.ToLocalTime().ToString("HH:mm", CultureInfo.InvariantCulture)}] "; + } + var color = message.FromSelf ? UIColors.Get("LightlessBlue") : ImGuiColors.DalamudWhite; + + ImGui.PushID(i); + ImGui.PushStyleColor(ImGuiCol.Text, color); + ImGui.TextWrapped($"{timestampText}{message.DisplayName}: {message.Payload.Message}"); + ImGui.PopStyleColor(); + + if (ImGui.BeginPopupContextItem($"chat_msg_ctx##{channel.Key}_{i}")) + { + foreach (var action in GetContextMenuActions(channel, message)) + { + if (ImGui.MenuItem(action.Label, string.Empty, false, action.IsEnabled)) + { + action.Execute(); + } + } + + ImGui.EndPopup(); + } + + ImGui.PopID(); + } + } + + if (_scrollToBottom) + { + ImGui.SetScrollHereY(1f); + _scrollToBottom = false; + } + } + + private void DrawInput(ChatChannelSnapshot channel) + { + const int MaxMessageLength = ZoneChatService.MaxOutgoingLength; + var canSend = channel.IsConnected && channel.IsAvailable; + _draftMessages.TryGetValue(channel.Key, out var draft); + draft ??= string.Empty; + + using (ImRaii.Disabled(!canSend)) + { + var style = ImGui.GetStyle(); + var sendButtonWidth = 100f * ImGuiHelpers.GlobalScale; + var counterWidth = ImGui.CalcTextSize($"{MaxMessageLength}/{MaxMessageLength}").X; + var reservedWidth = sendButtonWidth + counterWidth + style.ItemSpacing.X * 2f; + + ImGui.SetNextItemWidth(-reservedWidth); + var inputId = $"##chat-input-{channel.Key}"; + var send = ImGui.InputText(inputId, ref draft, MaxMessageLength, ImGuiInputTextFlags.EnterReturnsTrue); + _draftMessages[channel.Key] = draft; + + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey3); + ImGui.TextUnformatted($"{draft.Length}/{MaxMessageLength}"); + ImGui.PopStyleColor(); + + ImGui.SameLine(); + var buttonScreenPos = ImGui.GetCursorScreenPos(); + var rightEdgeScreen = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X; + var desiredButtonX = rightEdgeScreen - sendButtonWidth; + var minButtonX = buttonScreenPos.X + style.ItemSpacing.X; + var finalButtonX = MathF.Max(minButtonX, desiredButtonX); + ImGui.SetCursorScreenPos(new Vector2(finalButtonX, buttonScreenPos.Y)); + var sendColor = UIColors.Get("LightlessPurpleDefault"); + var sendHovered = UIColors.Get("LightlessPurple"); + var sendActive = UIColors.Get("LightlessPurpleActive"); + ImGui.PushStyleColor(ImGuiCol.Button, sendColor); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, sendHovered); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, sendActive); + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 6f * ImGuiHelpers.GlobalScale); + if (_uiSharedService.IconTextButton(FontAwesomeIcon.PaperPlane, "Send", 100f * ImGuiHelpers.GlobalScale, center: true)) + { + send = true; + } + ImGui.PopStyleVar(); + ImGui.PopStyleColor(3); + + if (send && TrySendDraft(channel, draft)) + { + _draftMessages[channel.Key] = string.Empty; + _scrollToBottom = true; + } + } + } + + private void DrawRulesOverlay() + { + var windowPos = ImGui.GetWindowPos(); + var windowSize = ImGui.GetWindowSize(); + var parentContentMin = ImGui.GetWindowContentRegionMin(); + var parentContentMax = ImGui.GetWindowContentRegionMax(); + var overlayPos = windowPos + parentContentMin; + var overlaySize = parentContentMax - parentContentMin; + + if (overlaySize.X <= 0f || overlaySize.Y <= 0f) + { + overlayPos = windowPos; + overlaySize = windowSize; + } + + ImGui.SetNextWindowFocus(); + ImGui.SetNextWindowPos(overlayPos); + ImGui.SetNextWindowSize(overlaySize); + ImGui.SetNextWindowBgAlpha(0.86f); + ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 6f * ImGuiHelpers.GlobalScale); + ImGui.PushStyleColor(ImGuiCol.Border, Vector4.Zero); + + var overlayFlags = ImGuiWindowFlags.NoDecoration + | ImGuiWindowFlags.NoMove + | ImGuiWindowFlags.NoScrollbar + | ImGuiWindowFlags.NoSavedSettings; + + var overlayOpen = true; + if (ImGui.Begin("##zone_chat_rules_overlay", ref overlayOpen, overlayFlags)) + { + var contentMin = ImGui.GetWindowContentRegionMin(); + var contentMax = ImGui.GetWindowContentRegionMax(); + var contentWidth = contentMax.X - contentMin.X; + var title = "Chat Rules"; + var titleWidth = ImGui.CalcTextSize(title).X; + + ImGui.SetCursorPosX(contentMin.X + Math.Max(0f, (contentWidth - titleWidth) * 0.5f)); + ImGui.TextUnformatted(title); + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + var style = ImGui.GetStyle(); + var buttonWidth = 180f * ImGuiHelpers.GlobalScale; + var buttonHeight = ImGui.GetFrameHeight(); + var buttonSpacing = Math.Max(0f, style.ItemSpacing.Y); + var buttonTopY = Math.Max(contentMin.Y, contentMax.Y - buttonHeight); + var childHeight = Math.Max(0f, buttonTopY - buttonSpacing - ImGui.GetCursorPosY()); + + using (var child = ImRaii.Child("zone_chat_rules_overlay_scroll", new Vector2(-1f, childHeight), false)) + { + if (child) + { + var childContentMin = ImGui.GetWindowContentRegionMin(); + var childContentMax = ImGui.GetWindowContentRegionMax(); + var childContentWidth = childContentMax.X - childContentMin.X; + + ImGui.PushTextWrapPos(childContentMin.X + childContentWidth); + + _uiSharedService.MediumText("Basic Chat Rules", UIColors.Get("LightlessBlue")); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("Do "), + new SeStringUtils.RichTextEntry("NOT share", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" confidential, personal, or account information-yours or anyone else's", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("Respect ALL participants; "), + new SeStringUtils.RichTextEntry("no harassment, hate speech, or personal attacks", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("AVOID ", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry("disruptive behaviors such as "), + new SeStringUtils.RichTextEntry("spamming or flooding", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("Absolutely "), + new SeStringUtils.RichTextEntry("NO discussion, sharing, or solicitation of illegal content or activities;", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(".")); + + ImGui.Dummy(new Vector2(5)); + + ImGui.Separator(); + _uiSharedService.MediumText("Zone Chat Rules", UIColors.Get("LightlessGreen")); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("NO ADVERTISEMENTS", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" whatsoever for any kind of "), + new SeStringUtils.RichTextEntry("services, venues, clubs, marketboard deals, or similar offerings", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(".")); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), + new SeStringUtils.RichTextEntry("Mature", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" or "), + new SeStringUtils.RichTextEntry("NSFW", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry(" content "), + new SeStringUtils.RichTextEntry("(including suggestive emotes, explicit innuendo, or roleplay (including requests) )", UIColors.Get("LightlessYellow"), true), + new SeStringUtils.RichTextEntry(" is"), + new SeStringUtils.RichTextEntry(" strictly prohibited ", UIColors.Get("DimRed"), true), + new SeStringUtils.RichTextEntry("in Zone Chat.")); + + ImGui.Dummy(new Vector2(5)); + + ImGui.Separator(); + _uiSharedService.MediumText("Syncshell Chat Rules", UIColors.Get("LightlessYellow")); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessYellow"), new SeStringUtils.RichTextEntry("Syncshell chats are self-moderated (their own set rules) by it's owner and appointed moderators. If they fail to enforce chat rules within their syncshell, the owner (and its moderators) may face punishment.")); + + ImGui.Dummy(new Vector2(5)); + + ImGui.Separator(); + _uiSharedService.MediumText("Reporting & Punishments", UIColors.Get("LightlessBlue")); + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessBlue"), + new SeStringUtils.RichTextEntry("Report rule-breakers by right clicking on the sent message and clicking report or via the mod-mail channel on the Discord."), + new SeStringUtils.RichTextEntry(" (False reports may be punished.) ", UIColors.Get("DimRed"), true)); + + _uiSharedService.DrawNoteLine("! ", UIColors.Get("LightlessBlue"), + new SeStringUtils.RichTextEntry("Punishments scale from a permanent chat ban up to a full Lightless account ban."), + new SeStringUtils.RichTextEntry(" (Appeals are NOT possible.) ", UIColors.Get("DimRed"), true)); + + ImGui.PopTextWrapPos(); + } + } + + var spacingStartY = Math.Max(ImGui.GetCursorPosY(), buttonTopY - buttonSpacing); + ImGui.SetCursorPosY(spacingStartY); + + if (buttonSpacing > 0f) + { + var actualSpacing = Math.Max(0f, buttonTopY - spacingStartY); + if (actualSpacing > 0f) + { + ImGui.Dummy(new Vector2(0f, actualSpacing)); + } + } + + ImGui.SetCursorPosY(buttonTopY); + + var buttonX = contentMin.X + Math.Max(0f, (contentWidth - buttonWidth) * 0.5f); + ImGui.SetCursorPosX(buttonX); + + if (ImGui.Button("I Understand", new Vector2(buttonWidth, buttonHeight))) + { + _showRulesOverlay = false; + } + + if (!overlayOpen) + { + _showRulesOverlay = false; + } + } + + ImGui.End(); + ImGui.PopStyleColor(); + ImGui.PopStyleVar(); + } + + private bool TrySendDraft(ChatChannelSnapshot channel, string draft) + { + var trimmed = draft.Trim(); + if (trimmed.Length == 0) + return false; + + bool succeeded; + try + { + succeeded = _zoneChatService.SendMessageAsync(channel.Descriptor, trimmed).GetAwaiter().GetResult(); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to send chat message"); + succeeded = false; + } + + return succeeded; + } + + private IEnumerable GetContextMenuActions(ChatChannelSnapshot channel, ChatMessageEntry message) + { + if (TryCreateCopyMessageAction(message, out var copyAction)) + { + yield return copyAction; + } + + if (TryCreateViewProfileAction(channel, message, out var viewProfile)) + { + yield return viewProfile; + } + } + + private bool TryCreateCopyMessageAction(ChatMessageEntry message, out ChatMessageContextAction action) + { + var text = message.Payload.Message; + if (string.IsNullOrEmpty(text)) + { + action = default; + return false; + } + + action = new ChatMessageContextAction( + "Copy Message", + true, + () => ImGui.SetClipboardText(text)); + return true; + } + + private bool TryCreateViewProfileAction(ChatChannelSnapshot channel, ChatMessageEntry message, out ChatMessageContextAction action) + { + action = default; + switch (channel.Type) + { + case ChatChannelType.Group: + { + var user = message.Payload.Sender.User; + if (user?.UID is not { Length: > 0 }) + return false; + + var snapshot = _pairUiService.GetSnapshot(); + if (snapshot.PairsByUid.TryGetValue(user.UID, out var pair) && pair is not null) + { + action = new ChatMessageContextAction( + "View Profile", + true, + () => Mediator.Publish(new ProfileOpenStandaloneMessage(pair))); + return true; + } + + action = new ChatMessageContextAction( + "View Profile", + true, + () => RunContextAction(() => OpenStandardProfileAsync(user))); + return true; + + } + + case ChatChannelType.Zone: + if (!message.Payload.Sender.CanResolveProfile) + return false; + + if (string.IsNullOrEmpty(message.Payload.Sender.Token)) + return false; + + action = new ChatMessageContextAction( + "View Profile", + true, + () => RunContextAction(() => OpenZoneParticipantProfileAsync(channel.Descriptor, message.Payload.Sender.Token))); + return true; + + default: + return false; + } + } + + private Task OpenStandardProfileAsync(UserData user) + { + _profileManager.GetLightlessProfile(user); + _profileManager.GetLightlessUserProfile(user); + Mediator.Publish(new OpenUserProfileMessage(user)); + return Task.CompletedTask; + } + + private void RunContextAction(Func action) + { + _ = Task.Run(async () => + { + try + { + await action().ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Chat context action failed"); + Mediator.Publish(new NotificationMessage("Zone Chat", "Action failed to complete.", NotificationType.Error, TimeSpan.FromSeconds(3))); + } + }); + } + + private async Task OpenZoneParticipantProfileAsync(ChatChannelDescriptor descriptor, string token) + { + var result = await _zoneChatService.ResolveParticipantAsync(descriptor, token).ConfigureAwait(false); + if (result is null) + { + Mediator.Publish(new NotificationMessage("Zone Chat", "Participant is no longer available.", NotificationType.Warning, TimeSpan.FromSeconds(3))); + return; + } + + var resolved = result.Value; + var hashedCid = resolved.Sender.HashedCid; + if (string.IsNullOrEmpty(hashedCid)) + { + Mediator.Publish(new NotificationMessage("Zone Chat", "This participant remains anonymous.", NotificationType.Warning, TimeSpan.FromSeconds(3))); + return; + } + + await OpenLightfinderProfileInternalAsync(hashedCid).ConfigureAwait(false); + } + + private async Task OpenLightfinderProfileInternalAsync(string hashedCid) + { + var profile = await _profileManager.GetLightfinderProfileAsync(hashedCid).ConfigureAwait(false); + if (profile is null) + { + Mediator.Publish(new NotificationMessage("Zone Chat", "Unable to load Lightfinder profile information.", NotificationType.Warning, TimeSpan.FromSeconds(3))); + return; + } + + var sanitizedUser = profile.Value.User with + { + UID = "Lightfinder User", + Alias = "Lightfinder User" + }; + + Mediator.Publish(new OpenLightfinderProfileMessage(sanitizedUser, profile.Value.ProfileData, hashedCid)); + } + + private void OnChatChannelMessageAdded(ChatChannelMessageAdded message) + { + if (_selectedChannelKey is not null && string.Equals(_selectedChannelKey, message.ChannelKey, StringComparison.Ordinal)) + { + _scrollToBottom = true; + } + } + + private void EnsureSelectedChannel(IReadOnlyList channels) + { + if (_selectedChannelKey is not null && channels.Any(channel => channel.Key == _selectedChannelKey)) + return; + + _selectedChannelKey = channels.Count > 0 ? channels[0].Key : null; + if (_selectedChannelKey is not null) + { + _zoneChatService.SetActiveChannel(_selectedChannelKey); + _scrollToBottom = true; + } + } + + private void CleanupDrafts(IReadOnlyList channels) + { + var existingKeys = new HashSet(channels.Select(c => c.Key), StringComparer.Ordinal); + foreach (var key in _draftMessages.Keys.ToList()) + { + if (!existingKeys.Contains(key)) + { + _draftMessages.Remove(key); + } + } + } + + private void DrawConnectionControls() + { + var hubState = _apiController.ServerState; + var chatEnabled = _zoneChatService.IsChatEnabled; + var chatConnected = _zoneChatService.IsChatConnected; + var buttonLabel = chatEnabled ? "Disable Chat" : "Enable Chat"; + var style = ImGui.GetStyle(); + var cursorStart = ImGui.GetCursorPos(); + var contentRightX = cursorStart.X + ImGui.GetContentRegionAvail().X; + var rulesButtonWidth = 90f * ImGuiHelpers.GlobalScale; + + using (ImRaii.Group()) + { + if (ImGui.Button(buttonLabel, new Vector2(130f * ImGuiHelpers.GlobalScale, 0f))) + { + ToggleChatConnection(chatEnabled); + } + + ImGui.SameLine(); + var chatStatusText = chatEnabled + ? (chatConnected ? "Chat: Connected" : "Chat: Waiting") + : "Chat: Disabled"; + var statusColor = chatEnabled + ? (chatConnected ? UIColors.Get("LightlessGreen") : UIColors.Get("LightlessYellow")) + : ImGuiColors.DalamudGrey3; + ImGui.PushStyleColor(ImGuiCol.Text, statusColor); + ImGui.TextUnformatted(chatStatusText); + ImGui.PopStyleColor(); + + if (!string.IsNullOrWhiteSpace(_apiController.AuthFailureMessage) && hubState == ServerState.Unauthorized) + { + ImGui.SameLine(); + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); + ImGui.TextUnformatted(_apiController.AuthFailureMessage); + ImGui.PopStyleColor(); + } + } + + var groupSize = ImGui.GetItemRectSize(); + var minBlockX = cursorStart.X + groupSize.X + style.ItemSpacing.X; + var availableAfterGroup = contentRightX - (cursorStart.X + groupSize.X); + var settingsButtonWidth = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Cog).X; + var pinIcon = _isWindowPinned ? FontAwesomeIcon.Lock : FontAwesomeIcon.Unlock; + var pinButtonWidth = _uiSharedService.GetIconButtonSize(pinIcon).X; + var blockWidth = rulesButtonWidth + style.ItemSpacing.X + settingsButtonWidth + style.ItemSpacing.X + pinButtonWidth; + var desiredBlockX = availableAfterGroup > blockWidth + style.ItemSpacing.X + ? contentRightX - blockWidth + : minBlockX; + desiredBlockX = Math.Max(cursorStart.X, desiredBlockX); + var rulesPos = new Vector2(desiredBlockX, cursorStart.Y); + var settingsPos = new Vector2(desiredBlockX + rulesButtonWidth + style.ItemSpacing.X, cursorStart.Y); + var pinPos = new Vector2(settingsPos.X + settingsButtonWidth + style.ItemSpacing.X, cursorStart.Y); + + ImGui.SameLine(); + ImGui.SetCursorPos(rulesPos); + if (ImGui.Button("Rules", new Vector2(rulesButtonWidth, 0f))) + { + _showRulesOverlay = true; + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Show chat rules"); + } + + ImGui.SameLine(); + ImGui.SetCursorPos(settingsPos); + if (_uiSharedService.IconButton(FontAwesomeIcon.Cog)) + { + ImGui.OpenPopup(SettingsPopupId); + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Chat settings"); + } + + ImGui.SameLine(); + ImGui.SetCursorPos(pinPos); + using (ImRaii.PushId("window_pin_button")) + { + var restorePinColors = false; + if (_isWindowPinned) + { + var pinBase = UIColors.Get("LightlessPurpleDefault"); + var pinHover = UIColors.Get("LightlessPurple").WithAlpha(0.9f); + var pinActive = UIColors.Get("LightlessPurpleActive"); + ImGui.PushStyleColor(ImGuiCol.Button, pinBase); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, pinHover); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, pinActive); + restorePinColors = true; + } + + var pinClicked = _uiSharedService.IconButton(pinIcon); + + if (restorePinColors) + { + ImGui.PopStyleColor(3); + } + + if (pinClicked) + { + ToggleWindowPinned(); + } + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(_isWindowPinned ? "Unpin window" : "Pin window"); + } + + DrawChatSettingsPopup(); + + ImGui.Separator(); + } + + private void ToggleWindowPinned() + { + _isWindowPinned = !_isWindowPinned; + _chatConfigService.Current.IsWindowPinned = _isWindowPinned; + _chatConfigService.Save(); + RefreshWindowFlags(); + } + + private void RefreshWindowFlags() + { + Flags = _unpinnedWindowFlags & ~ImGuiWindowFlags.NoCollapse; + if (_isWindowPinned) + { + Flags |= ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize; + } + } + + private void DrawChatSettingsPopup() + { + const ImGuiWindowFlags popupFlags = ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoSavedSettings; + if (!ImGui.BeginPopup(SettingsPopupId, popupFlags)) + return; + + ImGui.TextUnformatted("Chat Settings"); + ImGui.Separator(); + + var chatConfig = _chatConfigService.Current; + + var autoEnable = chatConfig.AutoEnableChatOnLogin; + if (ImGui.Checkbox("Auto-enable chat on login", ref autoEnable)) + { + chatConfig.AutoEnableChatOnLogin = autoEnable; + _chatConfigService.Save(); + if (autoEnable && !_zoneChatService.IsChatEnabled) + { + ToggleChatConnection(currentlyEnabled: false); + } + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Automatically connect to chat whenever Lightless loads."); + } + + var autoOpen = chatConfig.AutoOpenChatOnPluginLoad; + if (ImGui.Checkbox("Auto-open chat window on plugin load", ref autoOpen)) + { + chatConfig.AutoOpenChatOnPluginLoad = autoOpen; + _chatConfigService.Save(); + if (autoOpen) + { + IsOpen = true; + } + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Opens the chat window automatically whenever the plugin loads."); + } + + var showRules = chatConfig.ShowRulesOverlayOnOpen; + if (ImGui.Checkbox("Show rules overlay on open", ref showRules)) + { + chatConfig.ShowRulesOverlayOnOpen = showRules; + _chatConfigService.Save(); + _showRulesOverlay = showRules; + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Toggles if the rules popup appears everytime the chat is opened for the first time."); + } + + var showTimestamps = chatConfig.ShowMessageTimestamps; + if (ImGui.Checkbox("Show message timestamps", ref showTimestamps)) + { + chatConfig.ShowMessageTimestamps = showTimestamps; + _chatConfigService.Save(); + } + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Toggles the timestamp prefix on messages."); + } + + var windowOpacity = Math.Clamp(chatConfig.ChatWindowOpacity, MinWindowOpacity, MaxWindowOpacity); + var opacityChanged = ImGui.SliderFloat("Window transparency", ref windowOpacity, MinWindowOpacity, MaxWindowOpacity, "%.2f"); + var resetOpacity = ImGui.IsItemClicked(ImGuiMouseButton.Right); + if (resetOpacity) + { + windowOpacity = DefaultWindowOpacity; + opacityChanged = true; + } + + if (opacityChanged) + { + chatConfig.ChatWindowOpacity = windowOpacity; + _chatConfigService.Save(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Adjust transparency of the chat window.\nRight-click to reset to default."); + } + + ImGui.EndPopup(); + } + + private void ToggleChatConnection(bool currentlyEnabled) + { + _ = Task.Run(async () => + { + try + { + await _zoneChatService.SetChatEnabledAsync(!currentlyEnabled).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogWarning(ex, "Failed to toggle chat connection"); + } + }); + } + + private void DrawChannelButtons(IReadOnlyList channels) + { + var style = ImGui.GetStyle(); + var baseFramePadding = style.FramePadding; + var available = ImGui.GetContentRegionAvail().X; + var buttonHeight = ImGui.GetFrameHeight(); + var arrowWidth = buttonHeight; + var hasChannels = channels.Count > 0; + var scrollWidth = hasChannels ? Math.Max(0f, available - (arrowWidth * 2f + style.ItemSpacing.X * 2f)) : 0f; + if (hasChannels) + { + var minimumWidth = 120f * ImGuiHelpers.GlobalScale; + scrollWidth = Math.Max(scrollWidth, minimumWidth); + } + var scrollStep = scrollWidth > 0f ? scrollWidth * 0.9f : 120f; + if (!hasChannels) + { + _pendingChannelScroll = null; + _channelScroll = 0f; + _channelScrollMax = 0f; + } + var prevScroll = hasChannels ? _channelScroll : 0f; + var prevMax = hasChannels ? _channelScrollMax : 0f; + float currentScroll = prevScroll; + float maxScroll = prevMax; + + ImGui.PushID("chat_channel_buttons"); + ImGui.BeginGroup(); + + using (ImRaii.Disabled(!hasChannels || prevScroll <= 0.5f)) + { + var arrowNormal = UIColors.Get("ButtonDefault"); + var arrowHovered = UIColors.Get("LightlessPurple").WithAlpha(0.85f); + var arrowActive = UIColors.Get("LightlessPurpleDefault").WithAlpha(0.75f); + ImGui.PushStyleColor(ImGuiCol.Button, arrowNormal); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, arrowHovered); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, arrowActive); + var clickedLeft = ImGui.ArrowButton("##chat_left", ImGuiDir.Left); + ImGui.PopStyleColor(3); + if (clickedLeft) + { + _pendingChannelScroll = Math.Max(0f, currentScroll - scrollStep); + } + } + + ImGui.SameLine(0f, style.ItemSpacing.X); + + var childHeight = buttonHeight + style.FramePadding.Y * 2f + style.ScrollbarSize; + var alignPushed = false; + if (hasChannels) + { + ImGui.PushStyleVar(ImGuiStyleVar.ButtonTextAlign, new Vector2(0f, 0.5f)); + alignPushed = true; + } + + const int MaxBadgeDisplay = 99; + + using (var child = ImRaii.Child("channel_scroll", new Vector2(scrollWidth, childHeight), false, ImGuiWindowFlags.HorizontalScrollbar)) + { + if (child) + { + var first = true; + foreach (var channel in channels) + { + if (!first) + ImGui.SameLine(); + + var isSelected = string.Equals(channel.Key, _selectedChannelKey, StringComparison.Ordinal); + var showBadge = !isSelected && channel.UnreadCount > 0; + var isZoneChannel = channel.Type == ChatChannelType.Zone; + var badgeText = string.Empty; + var badgePadding = Vector2.Zero; + var badgeTextSize = Vector2.Zero; + float badgeWidth = 0f; + float badgeHeight = 0f; + + var normal = isSelected ? UIColors.Get("LightlessPurpleDefault") : UIColors.Get("ButtonDefault"); + var hovered = isSelected + ? UIColors.Get("LightlessPurple").WithAlpha(0.9f) + : UIColors.Get("ButtonDefault").WithAlpha(0.85f); + var active = isSelected + ? UIColors.Get("LightlessPurpleDefault").WithAlpha(0.8f) + : UIColors.Get("ButtonDefault").WithAlpha(0.75f); + + ImGui.PushStyleColor(ImGuiCol.Button, normal); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, hovered); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, active); + + if (showBadge) + { + var badgeSpacing = 4f * ImGuiHelpers.GlobalScale; + badgePadding = new Vector2(4f, 1.5f) * ImGuiHelpers.GlobalScale; + badgeText = channel.UnreadCount > MaxBadgeDisplay + ? $"{MaxBadgeDisplay}+" + : channel.UnreadCount.ToString(CultureInfo.InvariantCulture); + badgeTextSize = ImGui.CalcTextSize(badgeText); + badgeWidth = badgeTextSize.X + badgePadding.X * 2f; + badgeHeight = badgeTextSize.Y + badgePadding.Y * 2f; + var customPadding = new Vector2(baseFramePadding.X + badgeWidth + badgeSpacing, baseFramePadding.Y); + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, customPadding); + } + + var clicked = ImGui.Button($"{channel.DisplayName}##chat_channel_{channel.Key}"); + + if (showBadge) + { + ImGui.PopStyleVar(); + } + + ImGui.PopStyleColor(3); + + if (clicked && !isSelected) + { + _selectedChannelKey = channel.Key; + _zoneChatService.SetActiveChannel(channel.Key); + _scrollToBottom = true; + } + + var drawList = ImGui.GetWindowDrawList(); + var itemMin = ImGui.GetItemRectMin(); + var itemMax = ImGui.GetItemRectMax(); + + if (isZoneChannel) + { + var borderColor = UIColors.Get("LightlessOrange"); + var borderColorU32 = ImGui.ColorConvertFloat4ToU32(borderColor); + var borderThickness = Math.Max(1f, ImGuiHelpers.GlobalScale); + drawList.AddRect(itemMin, itemMax, borderColorU32, style.FrameRounding, ImDrawFlags.None, borderThickness); + } + + if (showBadge) + { + var buttonSizeY = itemMax.Y - itemMin.Y; + var badgeMin = new Vector2( + itemMin.X + baseFramePadding.X, + itemMin.Y + (buttonSizeY - badgeHeight) * 0.5f); + var badgeMax = badgeMin + new Vector2(badgeWidth, badgeHeight); + var badgeColor = UIColors.Get("DimRed"); + var badgeColorU32 = ImGui.ColorConvertFloat4ToU32(badgeColor); + drawList.AddRectFilled(badgeMin, badgeMax, badgeColorU32, badgeHeight * 0.5f); + var textPos = new Vector2( + badgeMin.X + (badgeWidth - badgeTextSize.X) * 0.5f, + badgeMin.Y + (badgeHeight - badgeTextSize.Y) * 0.5f); + drawList.AddText(textPos, ImGui.ColorConvertFloat4ToU32(ImGuiColors.DalamudWhite), badgeText); + } + + first = false; + } + + if (_pendingChannelScroll.HasValue) + { + ImGui.SetScrollX(_pendingChannelScroll.Value); + _pendingChannelScroll = null; + } + + currentScroll = ImGui.GetScrollX(); + maxScroll = ImGui.GetScrollMaxX(); + } + } + + if (alignPushed) + { + ImGui.PopStyleVar(); + } + + ImGui.SameLine(0f, style.ItemSpacing.X); + + using (ImRaii.Disabled(!hasChannels || prevScroll >= prevMax - 0.5f)) + { + var arrowNormal = UIColors.Get("ButtonDefault"); + var arrowHovered = UIColors.Get("LightlessPurple").WithAlpha(0.85f); + var arrowActive = UIColors.Get("LightlessPurpleDefault").WithAlpha(0.75f); + ImGui.PushStyleColor(ImGuiCol.Button, arrowNormal); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, arrowHovered); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, arrowActive); + var clickedRight = ImGui.ArrowButton("##chat_right", ImGuiDir.Right); + ImGui.PopStyleColor(3); + if (clickedRight) + { + _pendingChannelScroll = Math.Min(prevScroll + scrollStep, prevMax); + } + } + + ImGui.EndGroup(); + ImGui.PopID(); + + _channelScroll = currentScroll; + _channelScrollMax = maxScroll; + + ImGui.SetCursorPosY(ImGui.GetCursorPosY() - style.ItemSpacing.Y * 0.3f); + } + + private readonly record struct ChatMessageContextAction(string Label, bool IsEnabled, Action Execute); +} diff --git a/LightlessSync/Utils/Crypto.cs b/LightlessSync/Utils/Crypto.cs index c31f82f..f4d2469 100644 --- a/LightlessSync/Utils/Crypto.cs +++ b/LightlessSync/Utils/Crypto.cs @@ -1,4 +1,7 @@ -using System.Security.Cryptography; +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Security.Cryptography; using System.Text; namespace LightlessSync.Utils; @@ -9,8 +12,8 @@ public static class Crypto private const int _bufferSize = 65536; #pragma warning disable SYSLIB0021 // Type or member is obsolete - private static readonly Dictionary<(string, ushort), string> _hashListPlayersSHA256 = []; - private static readonly Dictionary _hashListSHA256 = new(StringComparer.Ordinal); + private static readonly ConcurrentDictionary<(string, ushort), string> _hashListPlayersSHA256 = new(); + private static readonly ConcurrentDictionary _hashListSHA256 = new(StringComparer.Ordinal); private static readonly SHA256CryptoServiceProvider _sha256CryptoProvider = new(); public static string GetFileHash(this string filePath) @@ -42,25 +45,18 @@ public static class Crypto public static string GetHash256(this (string, ushort) playerToHash) { - if (_hashListPlayersSHA256.TryGetValue(playerToHash, out var hash)) - return hash; - - return _hashListPlayersSHA256[playerToHash] = - BitConverter.ToString(_sha256CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(playerToHash.Item1 + playerToHash.Item2.ToString()))).Replace("-", "", StringComparison.Ordinal); + return _hashListPlayersSHA256.GetOrAdd(playerToHash, key => ComputeHashSHA256(key.Item1 + key.Item2.ToString())); } public static string GetHash256(this string stringToHash) { - return GetOrComputeHashSHA256(stringToHash); + return _hashListSHA256.GetOrAdd(stringToHash, ComputeHashSHA256); } - private static string GetOrComputeHashSHA256(string stringToCompute) + private static string ComputeHashSHA256(string stringToCompute) { - if (_hashListSHA256.TryGetValue(stringToCompute, out var hash)) - return hash; - - return _hashListSHA256[stringToCompute] = - BitConverter.ToString(_sha256CryptoProvider.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); + using var sha = SHA256.Create(); + return BitConverter.ToString(sha.ComputeHash(Encoding.UTF8.GetBytes(stringToCompute))).Replace("-", "", StringComparison.Ordinal); } #pragma warning restore SYSLIB0021 // Type or member is obsolete } \ No newline at end of file diff --git a/LightlessSync/Utils/SeStringUtils.cs b/LightlessSync/Utils/SeStringUtils.cs index 7507515..89ad891 100644 --- a/LightlessSync/Utils/SeStringUtils.cs +++ b/LightlessSync/Utils/SeStringUtils.cs @@ -4,9 +4,17 @@ using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface; using Dalamud.Interface.ImGuiSeStringRenderer; using Dalamud.Interface.Utility; +using Dalamud.Interface.Textures.TextureWraps; using Lumina.Text; +using Lumina.Text.Parse; +using Lumina.Text.ReadOnly; using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; using System.Numerics; +using System.Reflection; +using System.Text; using System.Threading; using DalamudSeString = Dalamud.Game.Text.SeStringHandling.SeString; using DalamudSeStringBuilder = Dalamud.Game.Text.SeStringHandling.SeStringBuilder; @@ -19,6 +27,438 @@ public static class SeStringUtils private static int _seStringHitboxCounter; private static int _iconHitboxCounter; + public static bool TryRenderSeStringMarkupAtCursor(string payload) + { + if (string.IsNullOrWhiteSpace(payload)) + return false; + + var wrapWidth = ImGui.GetContentRegionAvail().X; + if (wrapWidth <= 0f || float.IsNaN(wrapWidth) || float.IsInfinity(wrapWidth)) + wrapWidth = float.MaxValue; + + var normalizedPayload = payload.ReplaceLineEndings("
"); + try + { + _ = ReadOnlySeString.FromMacroString(normalizedPayload, new MacroStringParseOptions + { + ExceptionMode = MacroStringParseExceptionMode.Throw + }); + } + catch (Exception) + { + return false; + } + + try + { + var drawParams = new SeStringDrawParams + { + WrapWidth = wrapWidth, + Font = ImGui.GetFont(), + Color = ImGui.GetColorU32(ImGuiCol.Text), + }; + + var renderId = ImGui.GetID($"SeStringMarkup##{normalizedPayload.GetHashCode()}"); + var drawResult = ImGuiHelpers.CompileSeStringWrapped(normalizedPayload, drawParams, renderId); + var height = drawResult.Size.Y; + if (height <= 0f) + height = ImGui.GetTextLineHeight(); + + ImGui.Dummy(new Vector2(0f, height)); + + if (drawResult.InteractedPayloadEnvelope.Length > 0 && + TryExtractLink(drawResult.InteractedPayloadEnvelope, drawResult.InteractedPayload, out var linkUrl, out var tooltipText)) + { + var hoverText = !string.IsNullOrEmpty(linkUrl) ? linkUrl : tooltipText; + + if (!string.IsNullOrEmpty(hoverText)) + { + ImGui.BeginTooltip(); + ImGui.TextUnformatted(hoverText); + ImGui.EndTooltip(); + } + + if (!string.IsNullOrEmpty(linkUrl)) + ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); + + if (drawResult.Clicked && !string.IsNullOrEmpty(linkUrl)) + Dalamud.Utility.Util.OpenLink(linkUrl); + } + + return true; + } + catch (Exception ex) + { + ImGui.TextDisabled($"[SeString error] {ex.Message}"); + return false; + } + } + + public enum SeStringSegmentType + { + Text, + Icon + } + + public readonly record struct SeStringSegment( + SeStringSegmentType Type, + string? Text, + Vector4? Color, + uint IconId, + IDalamudTextureWrap? Texture, + Vector2 Size); + + public static bool TryResolveSegments( + string payload, + float scale, + Func iconResolver, + List resolvedSegments, + out Vector2 totalSize) + { + totalSize = Vector2.Zero; + if (string.IsNullOrWhiteSpace(payload)) + return false; + + var parsedSegments = new List(Math.Max(1, payload.Length / 4)); + if (!ParseSegments(payload, parsedSegments)) + return false; + + float width = 0f; + float height = 0f; + + foreach (var segment in parsedSegments) + { + switch (segment.Type) + { + case ParsedSegmentType.Text: + { + var text = segment.Text ?? string.Empty; + if (text.Length == 0) + break; + + var textSize = ImGui.CalcTextSize(text); + resolvedSegments.Add(new SeStringSegment(SeStringSegmentType.Text, text, segment.Color, 0, null, textSize)); + width += textSize.X; + height = MathF.Max(height, textSize.Y); + break; + } + case ParsedSegmentType.Icon: + { + var wrap = iconResolver(segment.IconId); + Vector2 iconSize; + string? fallback = null; + if (wrap != null) + { + iconSize = CalculateIconSize(wrap, scale); + } + else + { + fallback = $"[{segment.IconId}]"; + iconSize = ImGui.CalcTextSize(fallback); + } + + resolvedSegments.Add(new SeStringSegment(SeStringSegmentType.Icon, fallback, segment.Color, segment.IconId, wrap, iconSize)); + width += iconSize.X; + height = MathF.Max(height, iconSize.Y); + break; + } + } + } + + totalSize = new Vector2(width, height); + parsedSegments.Clear(); + return resolvedSegments.Count > 0; + } + + private enum ParsedSegmentType + { + Text, + Icon + } + + private readonly record struct ParsedSegment( + ParsedSegmentType Type, + string? Text, + uint IconId, + Vector4? Color); + + private static bool ParseSegments(string payload, List segments) + { + var builder = new StringBuilder(payload.Length); + Vector4? activeColor = null; + var index = 0; + while (index < payload.Length) + { + if (payload[index] == '<') + { + var end = payload.IndexOf('>', index); + if (end == -1) + break; + + var tagContent = payload.Substring(index + 1, end - index - 1); + if (TryHandleIconTag(tagContent, segments, builder, activeColor)) + { + index = end + 1; + continue; + } + + if (TryHandleColorTag(tagContent, segments, builder, ref activeColor)) + { + index = end + 1; + continue; + } + + builder.Append('<'); + builder.Append(tagContent); + builder.Append('>'); + index = end + 1; + } + else + { + builder.Append(payload[index]); + index++; + } + } + + if (index < payload.Length) + builder.Append(payload, index, payload.Length - index); + + FlushTextBuilder(builder, activeColor, segments); + return segments.Count > 0; + } + + private static bool TryHandleIconTag(string tagContent, List segments, StringBuilder textBuilder, Vector4? activeColor) + { + if (!tagContent.StartsWith("icon(", StringComparison.OrdinalIgnoreCase) || !tagContent.EndsWith(')')) + return false; + + var inner = tagContent.AsSpan(5, tagContent.Length - 6).Trim(); + if (!uint.TryParse(inner, NumberStyles.Integer, CultureInfo.InvariantCulture, out var iconId)) + return false; + + FlushTextBuilder(textBuilder, activeColor, segments); + segments.Add(new ParsedSegment(ParsedSegmentType.Icon, null, iconId, null)); + return true; + } + + private static bool TryHandleColorTag(string tagContent, List segments, StringBuilder textBuilder, ref Vector4? activeColor) + { + if (tagContent.StartsWith("color", StringComparison.OrdinalIgnoreCase)) + { + var equalsIndex = tagContent.IndexOf('='); + if (equalsIndex == -1) + return false; + + var value = tagContent.Substring(equalsIndex + 1).Trim().Trim('"'); + if (!TryParseColor(value, out var color)) + return false; + + FlushTextBuilder(textBuilder, activeColor, segments); + activeColor = color; + return true; + } + + if (tagContent.Equals("/color", StringComparison.OrdinalIgnoreCase)) + { + FlushTextBuilder(textBuilder, activeColor, segments); + activeColor = null; + return true; + } + + return false; + } + + private static void FlushTextBuilder(StringBuilder builder, Vector4? color, List segments) + { + if (builder.Length == 0) + return; + + segments.Add(new ParsedSegment(ParsedSegmentType.Text, builder.ToString(), 0, color)); + builder.Clear(); + } + + private static bool TryExtractLink(ReadOnlySpan envelope, Payload? payload, out string url, out string? tooltipText) + { + url = string.Empty; + tooltipText = null; + + if (envelope.Length == 0 && payload is null) + return false; + + tooltipText = envelope.Length > 0 ? DalamudSeString.Parse(envelope.ToArray()).TextValue : null; + + if (payload is not null && TryReadUrlFromPayload(payload, out url)) + return true; + + if (!string.IsNullOrWhiteSpace(tooltipText)) + { + var candidate = FindFirstUrl(tooltipText); + if (!string.IsNullOrEmpty(candidate)) + { + url = candidate; + return true; + } + } + + url = string.Empty; + return false; + } + + private static bool TryReadUrlFromPayload(object payload, out string url) + { + url = string.Empty; + var type = payload.GetType(); + + static string? ReadStringProperty(Type type, object instance, string propertyName) + => type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) + ?.GetValue(instance) as string; + + string? candidate = ReadStringProperty(type, payload, "Uri") + ?? ReadStringProperty(type, payload, "Url") + ?? ReadStringProperty(type, payload, "Target") + ?? ReadStringProperty(type, payload, "Destination"); + + if (IsHttpUrl(candidate)) + { + url = candidate!; + return true; + } + + var dataProperty = type.GetProperty("Data", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (dataProperty?.GetValue(payload) is IEnumerable sequence) + { + foreach (var entry in sequence) + { + if (IsHttpUrl(entry)) + { + url = entry; + return true; + } + } + } + + var extraStringProp = type.GetProperty("ExtraString", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (IsHttpUrl(extraStringProp?.GetValue(payload) as string)) + { + url = (extraStringProp!.GetValue(payload) as string)!; + return true; + } + + var textProp = type.GetProperty("Text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (IsHttpUrl(textProp?.GetValue(payload) as string)) + { + url = (textProp!.GetValue(payload) as string)!; + return true; + } + + return false; + } + + private static string? FindFirstUrl(string? text) + { + if (string.IsNullOrWhiteSpace(text)) + return null; + + var index = text.IndexOf("http", StringComparison.OrdinalIgnoreCase); + while (index >= 0) + { + var end = index; + while (end < text.Length && !char.IsWhiteSpace(text[end]) && !"\"')]>".Contains(text[end])) + end++; + + var candidate = text.Substring(index, end - index).TrimEnd('.', ',', ';'); + if (IsHttpUrl(candidate)) + return candidate; + + index = text.IndexOf("http", end, StringComparison.OrdinalIgnoreCase); + } + + return null; + } + + private static bool IsHttpUrl(string? value) + { + if (string.IsNullOrWhiteSpace(value)) + return false; + + return Uri.TryCreate(value, UriKind.Absolute, out var uri) + && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps); + } + + public static string StripMarkup(string value) + { + if (string.IsNullOrEmpty(value)) + return string.Empty; + + var builder = new StringBuilder(value.Length); + int depth = 0; + foreach (var c in value) + { + if (c == '<') + { + depth++; + continue; + } + + if (c == '>' && depth > 0) + { + depth--; + continue; + } + + if (depth == 0) + builder.Append(c); + } + + return builder.ToString().Trim(); + } + + private static bool TryParseColor(string value, out Vector4 color) + { + color = default; + if (string.IsNullOrEmpty(value) || value[0] != '#') + return false; + + var hex = value.AsSpan(1); + if (!uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var parsed)) + return false; + + byte a, r, g, b; + if (hex.Length == 6) + { + a = 0xFF; + r = (byte)(parsed >> 16); + g = (byte)(parsed >> 8); + b = (byte)parsed; + } + else if (hex.Length == 8) + { + a = (byte)(parsed >> 24); + r = (byte)(parsed >> 16); + g = (byte)(parsed >> 8); + b = (byte)parsed; + } + else + { + return false; + } + + const float inv = 1.0f / 255f; + color = new Vector4(r * inv, g * inv, b * inv, a * inv); + return true; + } + + private static Vector2 CalculateIconSize(IDalamudTextureWrap wrap, float scale) + { + const float IconHeightScale = 1.25f; + + var textHeight = ImGui.GetTextLineHeight(); + var baselineHeight = MathF.Max(1f, textHeight - 2f * scale); + var targetHeight = MathF.Max(baselineHeight, baselineHeight * IconHeightScale); + var aspect = wrap.Width > 0 ? wrap.Width / (float)wrap.Height : 1f; + return new Vector2(targetHeight * aspect, targetHeight); + } + public static DalamudSeString BuildFormattedPlayerName(string text, Vector4? textColor, Vector4? glowColor) { var b = new DalamudSeStringBuilder(); diff --git a/LightlessSync/Utils/VariousExtensions.cs b/LightlessSync/Utils/VariousExtensions.cs index 9215893..e0fd466 100644 --- a/LightlessSync/Utils/VariousExtensions.cs +++ b/LightlessSync/Utils/VariousExtensions.cs @@ -1,9 +1,10 @@ using Dalamud.Game.ClientState.Objects.Types; using LightlessSync.API.Data; using LightlessSync.API.Data.Enum; -using LightlessSync.PlayerData.Handlers; using LightlessSync.PlayerData.Pairs; using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; using System.Text.Json; namespace LightlessSync.Utils; @@ -56,9 +57,20 @@ public static class VariousExtensions } public static Dictionary> CheckUpdatedData(this CharacterData newData, Guid applicationBase, - CharacterData? oldData, ILogger logger, PairHandler cachedPlayer, bool forceApplyCustomization, bool forceApplyMods) + CharacterData? oldData, ILogger logger, IPairPerformanceSubject cachedPlayer, bool forceApplyCustomization, bool forceApplyMods) { oldData ??= new(); + static bool FileReplacementsEquivalent(ICollection left, ICollection right) + { + if (left.Count != right.Count) + { + return false; + } + + var comparer = LightlessSync.PlayerData.Data.FileReplacementDataComparer.Instance; + return !left.Except(right, comparer).Any() && !right.Except(left, comparer).Any(); + } + var charaDataToUpdate = new Dictionary>(); foreach (ObjectKind objectKind in Enum.GetValues()) { @@ -91,7 +103,9 @@ public static class VariousExtensions { if (hasNewAndOldFileReplacements) { - bool listsAreEqual = oldData.FileReplacements[objectKind].SequenceEqual(newData.FileReplacements[objectKind], PlayerData.Data.FileReplacementDataComparer.Instance); + var oldList = oldData.FileReplacements[objectKind]; + var newList = newData.FileReplacements[objectKind]; + var listsAreEqual = FileReplacementsEquivalent(oldList, newList); if (!listsAreEqual || forceApplyMods) { logger.LogDebug("[BASE-{appBase}] Updating {object}/{kind} (FileReplacements not equal) => {change}", applicationBase, cachedPlayer, objectKind, PlayerChanges.ModFiles); @@ -114,9 +128,9 @@ public static class VariousExtensions .OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList(); var newTail = newFileReplacements.Where(g => g.GamePaths.Any(p => p.Contains("/tail/", StringComparison.OrdinalIgnoreCase))) .OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList(); - var existingTransients = existingFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl") && !g.EndsWith("tex") && !g.EndsWith("mtrl"))) + var existingTransients = existingFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl", StringComparison.OrdinalIgnoreCase) && !g.EndsWith("tex", StringComparison.OrdinalIgnoreCase) && !g.EndsWith("mtrl", StringComparison.OrdinalIgnoreCase))) .OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList(); - var newTransients = newFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl") && !g.EndsWith("tex") && !g.EndsWith("mtrl"))) + var newTransients = newFileReplacements.Where(g => g.GamePaths.Any(g => !g.EndsWith("mdl", StringComparison.OrdinalIgnoreCase) && !g.EndsWith("tex", StringComparison.OrdinalIgnoreCase) && !g.EndsWith("mtrl", StringComparison.OrdinalIgnoreCase))) .OrderBy(g => string.IsNullOrEmpty(g.Hash) ? g.FileSwapPath : g.Hash, StringComparer.OrdinalIgnoreCase).ToList(); logger.LogTrace("[BASE-{appbase}] ExistingFace: {of}, NewFace: {fc}; ExistingHair: {eh}, NewHair: {nh}; ExistingTail: {et}, NewTail: {nt}; ExistingTransient: {etr}, NewTransient: {ntr}", applicationBase, diff --git a/LightlessSync/WebAPI/Files/FileDownloadManager.cs b/LightlessSync/WebAPI/Files/FileDownloadManager.cs index b8f81f2..d7fff31 100644 --- a/LightlessSync/WebAPI/Files/FileDownloadManager.cs +++ b/LightlessSync/WebAPI/Files/FileDownloadManager.cs @@ -7,6 +7,7 @@ using LightlessSync.FileCache; using LightlessSync.PlayerData.Handlers; using LightlessSync.Services; using LightlessSync.Services.Mediator; +using LightlessSync.Services.TextureCompression; using LightlessSync.WebAPI.Files.Models; using Microsoft.Extensions.Logging; using System; @@ -28,16 +29,23 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase private readonly FileTransferOrchestrator _orchestrator; private readonly PairProcessingLimiter _pairProcessingLimiter; private readonly LightlessConfigService _configService; + private readonly TextureDownscaleService _textureDownscaleService; + private readonly TextureMetadataHelper _textureMetadataHelper; private readonly ConcurrentDictionary _activeDownloadStreams; private static readonly TimeSpan DownloadStallTimeout = TimeSpan.FromSeconds(30); private volatile bool _disableDirectDownloads; private int _consecutiveDirectDownloadFailures; private bool _lastConfigDirectDownloadsState; - public FileDownloadManager(ILogger logger, LightlessMediator mediator, + public FileDownloadManager( + ILogger logger, + LightlessMediator mediator, FileTransferOrchestrator orchestrator, - FileCacheManager fileCacheManager, FileCompactor fileCompactor, - PairProcessingLimiter pairProcessingLimiter, LightlessConfigService configService) : base(logger, mediator) + FileCacheManager fileCacheManager, + FileCompactor fileCompactor, + PairProcessingLimiter pairProcessingLimiter, + LightlessConfigService configService, + TextureDownscaleService textureDownscaleService, TextureMetadataHelper textureMetadataHelper) : base(logger, mediator) { _downloadStatus = new Dictionary(StringComparer.Ordinal); _orchestrator = orchestrator; @@ -45,6 +53,8 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase _fileCompactor = fileCompactor; _pairProcessingLimiter = pairProcessingLimiter; _configService = configService; + _textureDownscaleService = textureDownscaleService; + _textureMetadataHelper = textureMetadataHelper; _activeDownloadStreams = new(); _lastConfigDirectDownloadsState = _configService.Current.EnableDirectDownloads; @@ -63,6 +73,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase public List CurrentDownloads { get; private set; } = []; public List ForbiddenTransfers => _orchestrator.ForbiddenTransfers; + public Guid? CurrentOwnerToken { get; private set; } public bool IsDownloading => CurrentDownloads.Any(); @@ -83,14 +94,15 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase { CurrentDownloads.Clear(); _downloadStatus.Clear(); + CurrentOwnerToken = null; } - public async Task DownloadFiles(GameObjectHandler gameObject, List fileReplacementDto, CancellationToken ct) + public async Task DownloadFiles(GameObjectHandler? gameObject, List fileReplacementDto, CancellationToken ct, bool skipDownscale = false) { Mediator.Publish(new HaltScanMessage(nameof(DownloadFiles))); try { - await DownloadFilesInternal(gameObject, fileReplacementDto, ct).ConfigureAwait(false); + await DownloadFilesInternal(gameObject, fileReplacementDto, ct, skipDownscale).ConfigureAwait(false); } catch { @@ -98,7 +110,10 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase } finally { - Mediator.Publish(new DownloadFinishedMessage(gameObject)); + if (gameObject is not null) + { + Mediator.Publish(new DownloadFinishedMessage(gameObject)); + } Mediator.Publish(new ResumeScanMessage(nameof(DownloadFiles))); } } @@ -272,7 +287,8 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase int bytesRead; try { - var readTask = stream.ReadAsync(buffer.AsMemory(0, buffer.Length), ct).AsTask(); + using var readCancellation = CancellationTokenSource.CreateLinkedTokenSource(ct); + var readTask = stream.ReadAsync(buffer.AsMemory(0, buffer.Length), readCancellation.Token).AsTask(); while (!readTask.IsCompleted) { var completedTask = await Task.WhenAny(readTask, Task.Delay(DownloadStallTimeout)).ConfigureAwait(false); @@ -286,6 +302,20 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase var snapshot = _pairProcessingLimiter.GetSnapshot(); if (snapshot.Waiting > 0) { + readCancellation.Cancel(); + try + { + await readTask.ConfigureAwait(false); + } + catch (OperationCanceledException) + { + // expected when cancelling the read due to timeout + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Error finishing read task after stall detection for {requestUrl}", requestUrl); + } + throw new TimeoutException($"No data received for {DownloadStallTimeout.TotalSeconds} seconds while downloading {requestUrl} (waiting: {snapshot.Waiting})"); } @@ -352,7 +382,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase } } - private async Task DecompressBlockFileAsync(string downloadStatusKey, string blockFilePath, List fileReplacement, string downloadLabel) + private async Task DecompressBlockFileAsync(string downloadStatusKey, string blockFilePath, List fileReplacement, string downloadLabel, bool skipDownscale) { if (_downloadStatus.TryGetValue(downloadStatusKey, out var status)) { @@ -385,7 +415,8 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase var decompressedFile = LZ4Wrapper.Unwrap(compressedFileContent); await _fileCompactor.WriteAllBytesAsync(filePath, decompressedFile, CancellationToken.None).ConfigureAwait(false); - PersistFileToStorage(fileHash, filePath); + var gamePath = fileReplacement.FirstOrDefault(f => string.Equals(f.Hash, fileHash, StringComparison.OrdinalIgnoreCase))?.GamePaths.FirstOrDefault() ?? string.Empty; + PersistFileToStorage(fileHash, filePath, gamePath, skipDownscale); } catch (EndOfStreamException) { @@ -413,7 +444,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase } private async Task PerformDirectDownloadFallbackAsync(DownloadFileTransfer directDownload, List fileReplacement, - IProgress progress, CancellationToken token, bool slotAlreadyAcquired) + IProgress progress, CancellationToken token, bool skipDownscale, bool slotAlreadyAcquired) { if (string.IsNullOrEmpty(directDownload.DirectDownloadUrl)) { @@ -455,7 +486,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase throw new FileNotFoundException("Block file missing after direct download fallback.", blockFile); } - await DecompressBlockFileAsync(downloadKey, blockFile, fileReplacement, $"fallback-{directDownload.Hash}").ConfigureAwait(false); + await DecompressBlockFileAsync(downloadKey, blockFile, fileReplacement, $"fallback-{directDownload.Hash}", skipDownscale).ConfigureAwait(false); } finally { @@ -478,8 +509,9 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase } } - public async Task> InitiateDownloadList(GameObjectHandler gameObjectHandler, List fileReplacement, CancellationToken ct) + public async Task> InitiateDownloadList(GameObjectHandler? gameObjectHandler, List fileReplacement, CancellationToken ct, Guid? ownerToken = null) { + CurrentOwnerToken = ownerToken; var objectName = gameObjectHandler?.Name ?? "Unknown"; Logger.LogDebug("Download start: {id}", objectName); @@ -520,7 +552,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase return CurrentDownloads; } - private async Task DownloadFilesInternal(GameObjectHandler gameObjectHandler, List fileReplacement, CancellationToken ct) + private async Task DownloadFilesInternal(GameObjectHandler? gameObjectHandler, List fileReplacement, CancellationToken ct, bool skipDownscale) { var objectName = gameObjectHandler?.Name ?? "Unknown"; @@ -583,7 +615,10 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase Logger.LogWarning("Downloading {direct} files directly, and {batchtotal} in {batches} batches.", directDownloads.Count, batchDownloads.Count, downloadBatches.Length); } - Mediator.Publish(new DownloadStartedMessage(gameObjectHandler, _downloadStatus)); + if (gameObjectHandler is not null) + { + Mediator.Publish(new DownloadStartedMessage(gameObjectHandler, _downloadStatus)); + } Task batchDownloadsTask = downloadBatches.Length == 0 ? Task.CompletedTask : Parallel.ForEachAsync(downloadBatches, new ParallelOptions() { @@ -651,7 +686,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase return; } - await DecompressBlockFileAsync(fileGroup.Key, blockFile, fileReplacement, fi.Name).ConfigureAwait(false); + await DecompressBlockFileAsync(fileGroup.Key, blockFile, fileReplacement, fi.Name, skipDownscale).ConfigureAwait(false); } finally { @@ -690,14 +725,13 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase if (!ShouldUseDirectDownloads()) { - await PerformDirectDownloadFallbackAsync(directDownload, fileReplacement, progress, token, slotAlreadyAcquired: false).ConfigureAwait(false); + await PerformDirectDownloadFallbackAsync(directDownload, fileReplacement, progress, token, skipDownscale, slotAlreadyAcquired: false).ConfigureAwait(false); return; } var tempFilename = _fileDbManager.GetCacheFilePath(directDownload.Hash, "bin"); var slotAcquired = false; - try { downloadTracker.DownloadStatus = DownloadStatus.WaitingForSlot; @@ -727,7 +761,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase byte[] compressedBytes = await File.ReadAllBytesAsync(tempFilename).ConfigureAwait(false); var decompressedBytes = LZ4Wrapper.Unwrap(compressedBytes); await _fileCompactor.WriteAllBytesAsync(finalFilename, decompressedBytes, CancellationToken.None).ConfigureAwait(false); - PersistFileToStorage(directDownload.Hash, finalFilename); + PersistFileToStorage(directDownload.Hash, finalFilename, replacement.GamePaths[0], skipDownscale); downloadTracker.TransferredFiles = 1; Logger.LogDebug("Finished direct download of {hash}.", directDownload.Hash); @@ -739,8 +773,15 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase } catch (OperationCanceledException ex) { - Logger.LogDebug("{hash}: Detected cancellation of direct download, discarding file.", directDownload.Hash); - Logger.LogError(ex, "{hash}: Error during direct download.", directDownload.Hash); + if (token.IsCancellationRequested) + { + Logger.LogDebug("{hash}: Direct download cancelled by caller, discarding file.", directDownload.Hash); + } + else + { + Logger.LogWarning(ex, "{hash}: Direct download cancelled unexpectedly.", directDownload.Hash); + } + ClearDownload(); return; } @@ -762,7 +803,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase try { downloadTracker.DownloadStatus = DownloadStatus.WaitingForQueue; - await PerformDirectDownloadFallbackAsync(directDownload, fileReplacement, progress, token, slotAcquired).ConfigureAwait(false); + await PerformDirectDownloadFallbackAsync(directDownload, fileReplacement, progress, token, skipDownscale, slotAcquired).ConfigureAwait(false); if (!expectedDirectDownloadFailure && failureCount >= 3 && !_disableDirectDownloads) { @@ -815,7 +856,7 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase return await response.Content.ReadFromJsonAsync>(cancellationToken: ct).ConfigureAwait(false) ?? []; } - private void PersistFileToStorage(string fileHash, string filePath) + private void PersistFileToStorage(string fileHash, string filePath, string gamePath, bool skipDownscale) { var fi = new FileInfo(filePath); Func RandomDayInThePast() @@ -832,6 +873,11 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase try { var entry = _fileDbManager.CreateCacheEntry(filePath); + var mapKind = _textureMetadataHelper.DetermineMapKind(gamePath, filePath); + if (!skipDownscale) + { + _textureDownscaleService.ScheduleDownscale(fileHash, filePath, mapKind); + } if (entry != null && !string.Equals(entry.Hash, fileHash, StringComparison.OrdinalIgnoreCase)) { Logger.LogError("Hash mismatch after extracting, got {hash}, expected {expectedHash}, deleting file", entry.Hash, fileHash); diff --git a/LightlessSync/WebAPI/Files/FileTransferOrchestrator.cs b/LightlessSync/WebAPI/Files/FileTransferOrchestrator.cs index de84a81..d6937c4 100644 --- a/LightlessSync/WebAPI/Files/FileTransferOrchestrator.cs +++ b/LightlessSync/WebAPI/Files/FileTransferOrchestrator.cs @@ -4,8 +4,10 @@ using LightlessSync.WebAPI.Files.Models; using LightlessSync.WebAPI.SignalR; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; +using System.Net.Http; using System.Net.Http.Headers; using System.Net.Http.Json; +using System.Net.Sockets; using System.Reflection; namespace LightlessSync.WebAPI.Files; @@ -84,27 +86,46 @@ public class FileTransferOrchestrator : DisposableMediatorSubscriberBase CancellationToken? ct = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, bool withToken = true) { - using var requestMessage = new HttpRequestMessage(method, uri); - return await SendRequestInternalAsync(requestMessage, ct, httpCompletionOption, withToken).ConfigureAwait(false); + return await SendRequestInternalAsync(() => new HttpRequestMessage(method, uri), + ct, httpCompletionOption, withToken, allowRetry: true).ConfigureAwait(false); } public async Task SendRequestAsync(HttpMethod method, Uri uri, T content, CancellationToken ct, bool withToken = true) where T : class { - using var requestMessage = new HttpRequestMessage(method, uri); - if (content is not ByteArrayContent) - requestMessage.Content = JsonContent.Create(content); - else - requestMessage.Content = content as ByteArrayContent; - return await SendRequestInternalAsync(requestMessage, ct, withToken: withToken).ConfigureAwait(false); + return await SendRequestInternalAsync(() => + { + var requestMessage = new HttpRequestMessage(method, uri); + if (content is not ByteArrayContent byteArrayContent) + { + requestMessage.Content = JsonContent.Create(content); + } + else + { + var clonedContent = new ByteArrayContent(byteArrayContent.ReadAsByteArrayAsync().GetAwaiter().GetResult()); + foreach (var header in byteArrayContent.Headers) + { + clonedContent.Headers.TryAddWithoutValidation(header.Key, header.Value); + } + requestMessage.Content = clonedContent; + } + + return requestMessage; + }, ct, HttpCompletionOption.ResponseContentRead, withToken, + allowRetry: content is not HttpContent || content is ByteArrayContent).ConfigureAwait(false); } public async Task SendRequestStreamAsync(HttpMethod method, Uri uri, ProgressableStreamContent content, CancellationToken ct, bool withToken = true) { - using var requestMessage = new HttpRequestMessage(method, uri); - requestMessage.Content = content; - return await SendRequestInternalAsync(requestMessage, ct, withToken: withToken).ConfigureAwait(false); + return await SendRequestInternalAsync(() => + { + var requestMessage = new HttpRequestMessage(method, uri) + { + Content = content + }; + return requestMessage; + }, ct, HttpCompletionOption.ResponseContentRead, withToken, allowRetry: false).ConfigureAwait(false); } public async Task WaitForDownloadSlotAsync(CancellationToken token) @@ -146,39 +167,78 @@ public class FileTransferOrchestrator : DisposableMediatorSubscriberBase return Math.Clamp(dividedLimit, 1, long.MaxValue); } - private async Task SendRequestInternalAsync(HttpRequestMessage requestMessage, - CancellationToken? ct = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, bool withToken = true) + private async Task SendRequestInternalAsync(Func requestFactory, + CancellationToken? ct = null, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead, + bool withToken = true, bool allowRetry = true) { - if (withToken) - { - var token = await _tokenProvider.GetToken().ConfigureAwait(false); - requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); - } + const int maxAttempts = 2; + var attempt = 0; - if (requestMessage.Content != null && requestMessage.Content is not StreamContent && requestMessage.Content is not ByteArrayContent) + while (true) { - var content = await ((JsonContent)requestMessage.Content).ReadAsStringAsync().ConfigureAwait(false); - Logger.LogDebug("Sending {method} to {uri} (Content: {content})", requestMessage.Method, requestMessage.RequestUri, content); - } - else - { - Logger.LogDebug("Sending {method} to {uri}", requestMessage.Method, requestMessage.RequestUri); - } + attempt++; + using var requestMessage = requestFactory(); - try - { - if (ct != null) - return await _httpClient.SendAsync(requestMessage, httpCompletionOption, ct.Value).ConfigureAwait(false); - return await _httpClient.SendAsync(requestMessage, httpCompletionOption).ConfigureAwait(false); - } - catch (TaskCanceledException) - { - throw; - } - catch (Exception ex) - { - Logger.LogWarning(ex, "Error during SendRequestInternal for {uri}", requestMessage.RequestUri); - throw; + if (withToken) + { + var token = await _tokenProvider.GetToken().ConfigureAwait(false); + requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token); + } + + if (requestMessage.Content != null && requestMessage.Content is not StreamContent && requestMessage.Content is not ByteArrayContent) + { + var content = await ((JsonContent)requestMessage.Content).ReadAsStringAsync().ConfigureAwait(false); + Logger.LogDebug("Sending {method} to {uri} (Content: {content})", requestMessage.Method, requestMessage.RequestUri, content); + } + else + { + Logger.LogDebug("Sending {method} to {uri}", requestMessage.Method, requestMessage.RequestUri); + } + + try + { + if (ct != null) + return await _httpClient.SendAsync(requestMessage, httpCompletionOption, ct.Value).ConfigureAwait(false); + return await _httpClient.SendAsync(requestMessage, httpCompletionOption).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + throw; + } + catch (Exception ex) when (allowRetry && attempt < maxAttempts && IsTransientNetworkException(ex)) + { + Logger.LogWarning(ex, "Transient error during SendRequestInternal for {uri}, retrying attempt {attempt}/{maxAttempts}", + requestMessage.RequestUri, attempt, maxAttempts); + if (ct.HasValue) + { + await Task.Delay(TimeSpan.FromMilliseconds(200), ct.Value).ConfigureAwait(false); + } + else + { + await Task.Delay(TimeSpan.FromMilliseconds(200)).ConfigureAwait(false); + } + } + catch (Exception ex) + { + Logger.LogWarning(ex, "Error during SendRequestInternal for {uri}", requestMessage.RequestUri); + throw; + } } } + + private static bool IsTransientNetworkException(Exception ex) + { + var current = ex; + while (current != null) + { + if (current is SocketException socketEx) + { + return socketEx.SocketErrorCode is SocketError.ConnectionReset or SocketError.ConnectionAborted or SocketError.TimedOut; + } + + current = current.InnerException; + } + + return false; + } } \ No newline at end of file diff --git a/LightlessSync/WebAPI/Files/FileUploadManager.cs b/LightlessSync/WebAPI/Files/FileUploadManager.cs index 09be269..4fb89b7 100644 --- a/LightlessSync/WebAPI/Files/FileUploadManager.cs +++ b/LightlessSync/WebAPI/Files/FileUploadManager.cs @@ -44,6 +44,7 @@ public sealed class FileUploadManager : DisposableMediatorSubscriberBase } public List CurrentUploads { get; } = []; + public bool IsReady => _orchestrator.IsInitialized; public bool IsUploading { get diff --git a/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs b/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs index a4c78f8..0a39219 100644 --- a/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs +++ b/LightlessSync/WebAPI/SignalR/ApIController.Functions.Users.cs @@ -1,5 +1,6 @@ -using LightlessSync.API.Data; +using LightlessSync.API.Data; using LightlessSync.API.Dto; +using LightlessSync.API.Dto.Chat; using LightlessSync.API.Dto.Group; using LightlessSync.API.Dto.User; using Microsoft.AspNetCore.SignalR.Client; @@ -41,6 +42,30 @@ public partial class ApiController await _lightlessHub!.SendAsync(nameof(TryPairWithContentId), otherCid).ConfigureAwait(false); } + public async Task UpdateChatPresence(ChatPresenceUpdateDto presence) + { + if (!IsConnected || _lightlessHub is null) return; + await _lightlessHub.InvokeAsync(nameof(UpdateChatPresence), presence).ConfigureAwait(false); + } + + public async Task SendChatMessage(ChatSendRequestDto request) + { + if (!IsConnected || _lightlessHub is null) return; + await _lightlessHub.InvokeAsync(nameof(SendChatMessage), request).ConfigureAwait(false); + } + + public async Task ReportChatMessage(ChatReportSubmitDto request) + { + if (!IsConnected || _lightlessHub is null) return; + await _lightlessHub.InvokeAsync(nameof(ReportChatMessage), request).ConfigureAwait(false); + } + + public async Task ResolveChatParticipant(ChatParticipantResolveRequestDto request) + { + if (!IsConnected || _lightlessHub is null) return null; + return await _lightlessHub.InvokeAsync(nameof(ResolveChatParticipant), request).ConfigureAwait(false); + } + public async Task SetBroadcastStatus(bool enabled, GroupBroadcastRequestDto? groupDto = null) { CheckConnection(); @@ -88,6 +113,12 @@ public partial class ApiController return await _lightlessHub!.InvokeAsync(nameof(UserGetProfile), dto).ConfigureAwait(false); } + public async Task UserGetLightfinderProfile(string hashedCid) + { + if (!IsConnected) return null; + return await _lightlessHub!.InvokeAsync(nameof(UserGetLightfinderProfile), hashedCid).ConfigureAwait(false); + } + public async Task UserPushData(UserCharaDataMessageDto dto) { try diff --git a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs index 8323fc3..490800f 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.Functions.Callbacks.cs @@ -1,7 +1,9 @@ +using System; using LightlessSync.API.Data; using LightlessSync.API.Data.Enum; using LightlessSync.API.Dto; using LightlessSync.API.Dto.CharaData; +using LightlessSync.API.Dto.Chat; using LightlessSync.API.Dto.Group; using LightlessSync.API.Dto.User; using LightlessSync.LightlessConfiguration.Models; @@ -24,21 +26,21 @@ public partial class ApiController public Task Client_GroupChangePermissions(GroupPermissionDto groupPermission) { Logger.LogTrace("Client_GroupChangePermissions: {perm}", groupPermission); - ExecuteSafely(() => _pairManager.SetGroupPermissions(groupPermission)); + ExecuteSafely(() => _pairCoordinator.HandleGroupChangePermissions(groupPermission)); return Task.CompletedTask; } public Task Client_GroupChangeUserPairPermissions(GroupPairUserPermissionDto dto) { Logger.LogDebug("Client_GroupChangeUserPairPermissions: {dto}", dto); - ExecuteSafely(() => _pairManager.UpdateGroupPairPermissions(dto)); + ExecuteSafely(() => _pairCoordinator.HandleGroupPairPermissions(dto)); return Task.CompletedTask; } public Task Client_GroupDelete(GroupDto groupDto) { Logger.LogTrace("Client_GroupDelete: {dto}", groupDto); - ExecuteSafely(() => _pairManager.RemoveGroup(groupDto.Group)); + ExecuteSafely(() => _pairCoordinator.HandleGroupRemoved(groupDto)); return Task.CompletedTask; } @@ -47,8 +49,8 @@ public partial class ApiController Logger.LogTrace("Client_GroupPairChangeUserInfo: {dto}", userInfo); ExecuteSafely(() => { - if (string.Equals(userInfo.UID, UID, StringComparison.Ordinal)) _pairManager.SetGroupStatusInfo(userInfo); - else _pairManager.SetGroupPairStatusInfo(userInfo); + var isSelf = string.Equals(userInfo.UID, UID, StringComparison.Ordinal); + _pairCoordinator.HandleGroupPairStatus(userInfo, isSelf); }); return Task.CompletedTask; } @@ -56,28 +58,28 @@ public partial class ApiController public Task Client_GroupPairJoined(GroupPairFullInfoDto groupPairInfoDto) { Logger.LogTrace("Client_GroupPairJoined: {dto}", groupPairInfoDto); - ExecuteSafely(() => _pairManager.AddGroupPair(groupPairInfoDto)); + ExecuteSafely(() => _pairCoordinator.HandleGroupPairJoined(groupPairInfoDto)); return Task.CompletedTask; } public Task Client_GroupPairLeft(GroupPairDto groupPairDto) { Logger.LogTrace("Client_GroupPairLeft: {dto}", groupPairDto); - ExecuteSafely(() => _pairManager.RemoveGroupPair(groupPairDto)); + ExecuteSafely(() => _pairCoordinator.HandleGroupPairLeft(groupPairDto)); return Task.CompletedTask; } public Task Client_GroupSendFullInfo(GroupFullInfoDto groupInfo) { Logger.LogTrace("Client_GroupSendFullInfo: {dto}", groupInfo); - ExecuteSafely(() => _pairManager.AddGroup(groupInfo)); + ExecuteSafely(() => _pairCoordinator.HandleGroupFullInfo(groupInfo)); return Task.CompletedTask; } public Task Client_GroupSendInfo(GroupInfoDto groupInfo) { Logger.LogTrace("Client_GroupSendInfo: {dto}", groupInfo); - ExecuteSafely(() => _pairManager.SetGroupInfo(groupInfo)); + ExecuteSafely(() => _pairCoordinator.HandleGroupInfoUpdate(groupInfo)); return Task.CompletedTask; } @@ -129,52 +131,62 @@ public partial class ApiController return Task.CompletedTask; } + public Task Client_ChatReceive(ChatMessageDto message) + { + Logger.LogTrace("Client_ChatReceive: {@channel}", message.Channel); + ExecuteSafely(() => ChatMessageReceived?.Invoke(message)); + return Task.CompletedTask; + } + public Task Client_UpdateUserIndividualPairStatusDto(UserIndividualPairStatusDto dto) { Logger.LogDebug("Client_UpdateUserIndividualPairStatusDto: {dto}", dto); - ExecuteSafely(() => _pairManager.UpdateIndividualPairStatus(dto)); + ExecuteSafely(() => _pairCoordinator.HandleUserStatus(dto)); return Task.CompletedTask; } public Task Client_UserAddClientPair(UserPairDto dto) { Logger.LogDebug("Client_UserAddClientPair: {dto}", dto); - ExecuteSafely(() => _pairManager.AddUserPair(dto, addToLastAddedUser: true)); + ExecuteSafely(() => _pairCoordinator.HandleUserAddPair(dto, addToLastAddedUser: true)); return Task.CompletedTask; } public Task Client_UserReceiveCharacterData(OnlineUserCharaDataDto dataDto) { Logger.LogTrace("Client_UserReceiveCharacterData: {user}", dataDto.User); - ExecuteSafely(() => _pairManager.ReceiveCharaData(dataDto)); + ExecuteSafely(() => _pairCoordinator.HandleCharacterData(dataDto)); return Task.CompletedTask; } public Task Client_UserReceiveUploadStatus(UserDto dto) { Logger.LogTrace("Client_UserReceiveUploadStatus: {dto}", dto); - ExecuteSafely(() => _pairManager.ReceiveUploadStatus(dto)); + ExecuteSafely(() => + { + _pairCoordinator.HandleUploadStatus(dto); + }); return Task.CompletedTask; } public Task Client_UserRemoveClientPair(UserDto dto) { Logger.LogDebug("Client_UserRemoveClientPair: {dto}", dto); - ExecuteSafely(() => _pairManager.RemoveUserPair(dto)); + ExecuteSafely(() => _pairCoordinator.HandleUserRemovePair(dto)); return Task.CompletedTask; } public Task Client_UserSendOffline(UserDto dto) { Logger.LogDebug("Client_UserSendOffline: {dto}", dto); - ExecuteSafely(() => _pairManager.MarkPairOffline(dto.User)); + ExecuteSafely(() => _pairCoordinator.HandleUserOffline(dto.User)); return Task.CompletedTask; } public Task Client_UserSendOnline(OnlineUserIdentDto dto) { Logger.LogDebug("Client_UserSendOnline: {dto}", dto); - ExecuteSafely(() => _pairManager.MarkPairOnline(dto)); + ExecuteSafely(() => _pairCoordinator.HandleUserOnline(dto, sendNotification: true)); return Task.CompletedTask; } @@ -188,7 +200,7 @@ public partial class ApiController public Task Client_UserUpdateOtherPairPermissions(UserPermissionsDto dto) { Logger.LogDebug("Client_UserUpdateOtherPairPermissions: {dto}", dto); - ExecuteSafely(() => _pairManager.UpdatePairPermissions(dto)); + ExecuteSafely(() => _pairCoordinator.HandleUserPermissions(dto)); return Task.CompletedTask; } @@ -209,7 +221,7 @@ public partial class ApiController public Task Client_UserUpdateSelfPairPermissions(UserPermissionsDto dto) { Logger.LogDebug("Client_UserUpdateSelfPairPermissions: {dto}", dto); - ExecuteSafely(() => _pairManager.UpdateSelfPairPermissions(dto)); + ExecuteSafely(() => _pairCoordinator.HandleSelfPermissions(dto)); return Task.CompletedTask; } diff --git a/LightlessSync/WebAPI/SignalR/ApiController.cs b/LightlessSync/WebAPI/SignalR/ApiController.cs index d2fddc5..c184fdb 100644 --- a/LightlessSync/WebAPI/SignalR/ApiController.cs +++ b/LightlessSync/WebAPI/SignalR/ApiController.cs @@ -1,9 +1,14 @@ +using System; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; using Dalamud.Utility; using LightlessSync.API.Data; using LightlessSync.API.Data.Extensions; using LightlessSync.API.Dto; using LightlessSync.API.Dto.Chat; using LightlessSync.API.Dto.Group; +using LightlessSync.API.Dto.Chat; using LightlessSync.API.Dto.User; using LightlessSync.API.SignalR; using LightlessSync.LightlessConfiguration; @@ -16,7 +21,6 @@ using LightlessSync.WebAPI.SignalR; using LightlessSync.WebAPI.SignalR.Utils; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.Logging; -using System.Reflection; namespace LightlessSync.WebAPI; @@ -28,7 +32,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL private readonly DalamudUtilService _dalamudUtil; private readonly HubFactory _hubFactory; - private readonly PairManager _pairManager; + private readonly PairCoordinator _pairCoordinator; private readonly PairRequestService _pairRequestService; private readonly ServerConfigurationManager _serverManager; private readonly TokenProvider _tokenProvider; @@ -42,14 +46,17 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL private HubConnection? _lightlessHub; private ServerState _serverState; private CensusUpdateMessage? _lastCensus; + private IReadOnlyList _zoneChatChannels = Array.Empty(); + private IReadOnlyList _groupChatChannels = Array.Empty(); + private event Action? ChatMessageReceived; public ApiController(ILogger logger, HubFactory hubFactory, DalamudUtilService dalamudUtil, - PairManager pairManager, PairRequestService pairRequestService, ServerConfigurationManager serverManager, LightlessMediator mediator, + PairCoordinator pairCoordinator, PairRequestService pairRequestService, ServerConfigurationManager serverManager, LightlessMediator mediator, TokenProvider tokenProvider, LightlessConfigService lightlessConfigService, NotificationService lightlessNotificationService) : base(logger, mediator) { _hubFactory = hubFactory; _dalamudUtil = dalamudUtil; - _pairManager = pairManager; + _pairCoordinator = pairCoordinator; _pairRequestService = pairRequestService; _serverManager = serverManager; _tokenProvider = tokenProvider; @@ -61,7 +68,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL Mediator.Subscribe(this, (msg) => LightlessHubOnClosed(msg.Exception)); Mediator.Subscribe(this, (msg) => _ = LightlessHubOnReconnectedAsync()); Mediator.Subscribe(this, (msg) => LightlessHubOnReconnecting(msg.Exception)); - Mediator.Subscribe(this, (msg) => _ = CyclePauseAsync(msg.UserData)); + Mediator.Subscribe(this, (msg) => _ = CyclePauseAsync(msg.Pair)); Mediator.Subscribe(this, (msg) => _lastCensus = msg); Mediator.Subscribe(this, (msg) => _ = PauseAsync(msg.UserData)); @@ -106,15 +113,65 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL public SystemInfoDto SystemInfoDto { get; private set; } = new(); + public IReadOnlyList ZoneChatChannels => _zoneChatChannels; + public IReadOnlyList GroupChatChannels => _groupChatChannels; public string UID => _connectionDto?.User.UID ?? string.Empty; public event Action? OnConnected; public async Task CheckClientHealth() { - return await _lightlessHub!.InvokeAsync(nameof(CheckClientHealth)).ConfigureAwait(false); + var hub = _lightlessHub; + if (hub is null || !IsConnected) + { + return false; + } + + try + { + return await hub.InvokeAsync(nameof(CheckClientHealth)).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.LogDebug(ex, "Client health check failed."); + return false; + } } + public async Task RefreshChatChannelsAsync() + { + if (_lightlessHub is null || !IsConnected) + return; + + await Task.WhenAll(GetZoneChatChannelsAsync(), GetGroupChatChannelsAsync()).ConfigureAwait(false); + } + + public async Task> GetZoneChatChannelsAsync() + { + if (_lightlessHub is null || !IsConnected) + return _zoneChatChannels; + + var channels = await _lightlessHub.InvokeAsync>("GetZoneChatChannels").ConfigureAwait(false); + _zoneChatChannels = channels; + return channels; + } + + public async Task> GetGroupChatChannelsAsync() + { + if (_lightlessHub is null || !IsConnected) + return _groupChatChannels; + + var channels = await _lightlessHub.InvokeAsync>("GetGroupChatChannels").ConfigureAwait(false); + _groupChatChannels = channels; + return channels; + } + + Task> ILightlessHub.GetZoneChatChannels() + => _lightlessHub!.InvokeAsync>("GetZoneChatChannels"); + + Task> ILightlessHub.GetGroupChatChannels() + => _lightlessHub!.InvokeAsync>("GetGroupChatChannels"); + public async Task CreateConnectionsAsync() { if (!_serverManager.ShownCensusPopup) @@ -337,35 +394,86 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL private bool _naggedAboutLod = false; - public Task CyclePauseAsync(UserData userData) + public Task CyclePauseAsync(Pair pair) { - CancellationTokenSource cts = new(); - cts.CancelAfter(TimeSpan.FromSeconds(5)); + ArgumentNullException.ThrowIfNull(pair); + return CyclePauseAsync(pair.UniqueIdent); + } + + public Task CyclePauseAsync(PairUniqueIdentifier ident) + { + var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(8)); _ = Task.Run(async () => { - var pair = _pairManager.GetOnlineUserPairs().Single(p => p.UserPair != null && p.UserData == userData); - var perm = pair.UserPair!.OwnPermissions; - perm.SetPaused(paused: true); - await UserSetPairPermissions(new UserPermissionsDto(userData, perm)).ConfigureAwait(false); - // wait until it's changed - while (pair.UserPair!.OwnPermissions != perm) + var token = timeoutCts.Token; + try { - await Task.Delay(250, cts.Token).ConfigureAwait(false); - Logger.LogTrace("Waiting for permissions change for {data}", userData); + if (!_pairCoordinator.Ledger.TryGetEntry(ident, out var entry) || entry is null) + { + Logger.LogWarning("CyclePauseAsync: pair {uid} not found in ledger", ident.UserId); + return; + } + + var originalPermissions = entry.SelfPermissions; + var targetPermissions = originalPermissions; + targetPermissions.SetPaused(!originalPermissions.IsPaused()); + + await UserSetPairPermissions(new UserPermissionsDto(entry.User, targetPermissions)).ConfigureAwait(false); + + var applied = false; + while (!token.IsCancellationRequested) + { + if (_pairCoordinator.Ledger.TryGetEntry(ident, out var updated) && updated is not null) + { + if (updated.SelfPermissions == targetPermissions) + { + applied = true; + entry = updated; + break; + } + } + + await Task.Delay(250, token).ConfigureAwait(false); + Logger.LogTrace("Waiting for permissions change for {uid}", ident.UserId); + } + + if (!applied) + { + Logger.LogWarning("CyclePauseAsync timed out waiting for pause acknowledgement for {uid}", ident.UserId); + return; + } + + Logger.LogDebug("CyclePauseAsync toggled paused for {uid} to {state}", ident.UserId, targetPermissions.IsPaused()); } - perm.SetPaused(paused: false); - await UserSetPairPermissions(new UserPermissionsDto(userData, perm)).ConfigureAwait(false); - }, cts.Token).ContinueWith((t) => cts.Dispose()); + catch (OperationCanceledException) + { + Logger.LogDebug("CyclePauseAsync cancelled for {uid}", ident.UserId); + } + catch (Exception ex) + { + Logger.LogWarning(ex, "CyclePauseAsync failed for {uid}", ident.UserId); + } + finally + { + timeoutCts.Dispose(); + } + }, CancellationToken.None); return Task.CompletedTask; } public async Task PauseAsync(UserData userData) { - var pair = _pairManager.GetOnlineUserPairs().Single(p => p.UserPair != null && p.UserData == userData); - var perm = pair.UserPair!.OwnPermissions; - perm.SetPaused(paused: true); - await UserSetPairPermissions(new UserPermissionsDto(userData, perm)).ConfigureAwait(false); + var pairIdent = new PairUniqueIdentifier(userData.UID); + if (!_pairCoordinator.Ledger.TryGetEntry(pairIdent, out var entry) || entry is null) + { + Logger.LogWarning("PauseAsync: pair {uid} not found in ledger", userData.UID); + return; + } + + var permissions = entry.SelfPermissions; + permissions.SetPaused(paused: true); + await UserSetPairPermissions(new UserPermissionsDto(userData, permissions)).ConfigureAwait(false); } public Task GetConnectionDto() => GetConnectionDtoAsync(true); @@ -388,8 +496,13 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL private async Task ClientHealthCheckAsync(CancellationToken ct) { - while (!ct.IsCancellationRequested && _lightlessHub != null) + while (!ct.IsCancellationRequested) { + if (_lightlessHub is null) + { + break; + } + await Task.Delay(TimeSpan.FromSeconds(30), ct).ConfigureAwait(false); Logger.LogDebug("Checking Client Health State"); @@ -455,6 +568,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL OnGroupSendInfo((dto) => _ = Client_GroupSendInfo(dto)); OnGroupUpdateProfile((dto) => _ = Client_GroupSendProfile(dto)); OnGroupChangeUserPairPermissions((dto) => _ = Client_GroupChangeUserPairPermissions(dto)); + _lightlessHub.On(nameof(Client_ChatReceive), (Func)Client_ChatReceive); OnGposeLobbyJoin((dto) => _ = Client_GposeLobbyJoin(dto)); OnGposeLobbyLeave((dto) => _ = Client_GposeLobbyLeave(dto)); @@ -470,18 +584,36 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL _initialized = true; } + private readonly HashSet> _chatHandlers = new(); + + public void RegisterChatMessageHandler(Action handler) + { + if (_chatHandlers.Add(handler)) + { + ChatMessageReceived += handler; + } + } + + public void UnregisterChatMessageHandler(Action handler) + { + if (_chatHandlers.Remove(handler)) + { + ChatMessageReceived -= handler; + } + } + private async Task LoadIninitialPairsAsync() { foreach (var entry in await GroupsGetAll().ConfigureAwait(false)) { Logger.LogDebug("Group: {entry}", entry); - _pairManager.AddGroup(entry); + _pairCoordinator.HandleGroupFullInfo(entry); } foreach (var userPair in await UserGetPairedClients().ConfigureAwait(false)) { Logger.LogDebug("Individual Pair: {userPair}", userPair); - _pairManager.AddUserPair(userPair); + _pairCoordinator.HandleUserAddPair(userPair); } } @@ -498,7 +630,7 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL foreach (var entry in await UserGetOnlinePairs(dto).ConfigureAwait(false)) { Logger.LogDebug("Pair online: {pair}", entry); - _pairManager.MarkPairOnline(entry, sendNotif: false); + _pairCoordinator.HandleUserOnline(entry, sendNotification: false); } } @@ -602,49 +734,12 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IL Mediator.Publish(new DisconnectedMessage()); _lightlessHub = null; _connectionDto = null; + _zoneChatChannels = Array.Empty(); + _groupChatChannels = Array.Empty(); } ServerState = state; } - public Task UserGetLightfinderProfile(string hashedCid) - { - throw new NotImplementedException(); - } - - public Task UpdateChatPresence(ChatPresenceUpdateDto presence) - { - throw new NotImplementedException(); - } - - public Task Client_ChatReceive(ChatMessageDto message) - { - throw new NotImplementedException(); - } - - public Task> GetZoneChatChannels() - { - throw new NotImplementedException(); - } - - public Task> GetGroupChatChannels() - { - throw new NotImplementedException(); - } - - public Task SendChatMessage(ChatSendRequestDto request) - { - throw new NotImplementedException(); - } - - public Task ReportChatMessage(ChatReportSubmitDto request) - { - throw new NotImplementedException(); - } - - public Task ResolveChatParticipant(ChatParticipantResolveRequestDto request) - { - throw new NotImplementedException(); - } } -#pragma warning restore MA0040 \ No newline at end of file +#pragma warning restore MA0040 diff --git a/LightlessSync/lib/DirectXTexC.dll b/LightlessSync/lib/DirectXTexC.dll new file mode 100644 index 0000000000000000000000000000000000000000..2cab1dcea5a148712aa14312788227fd61b8800d GIT binary patch literal 983552 zcmdqKdwf*Y)jvF$$&g40djdq_m1u*G#%gM;LPu*3%)l9#fhYumir_89dI7@>;sr@E ziDW#CO|4e@)K;xN6>F>3T8LO>l0Xs&mjI%82edllctNcp;AMW_?>^^DW-!=3@9%m4 zcwatD&ffd%%i3$Nwf5R;uf31|k`{~2VzFf7mrPnLt$6ZZh5Y;df1Fts%kVL4hg+UI zYRgHjS-veN&0KKp;^IZM3x8I7#SO(*U2)@$3j@VhUQ=8fys`M&8;jl3XB6MC@ak*M z%+DWMVpM(pGl#Y>-F|O_`Frxw`$NkSfAY~^hCVgYZ^84#%KJjM$!AMwiG1E4`ni1m zGBgvK=cjj2GI`y$@%sl%oCl}{gho5RWeTc>Key&VjIUSgE$Y34Nqlc{)3v$SR z=F>7?=txJZ)iNJh^+M+3yKy~b(Qk%ZO7bn1d;d7xQpp-Cgr%R){lhJFKViW5S1Bxy z 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�!4*`xQ10UwC4Us(p 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�VnY3HRJ|4@~S ziDXIAhNuACZK2FplNcxzv)5U0DBwittPRoI0QBPLUEtlA8d;E30s9 zUKgtPItO#DKe(DG+{yi|FkBZzOE}`J*E)mu5{9@${#+%Z!R1=zpEe+A67{!WqGzqg zwGpEM4zN%Va=KXO+zixB|9hM;=Rgxd`N=XtKCIGQA%$!7@^GTLL$w4LkmPo{Ozs;AW=egaItW56D z>DgRqvE?>_=gw+Que`H7I+!0horDbActg6LE!I`xTzJ;=EpL)9(M^6ceJ>nECzAid zL+R|H-_Y5-@bltV4ZywDT`L%0Qe1Vsva(b>Pur?C)%V|izFi{x&}z9^{q^|Rlhzz@ z!91*j+7{5OR^pn(mjAYJx!9;4vAL%v14wL}X$~Guq@P zobMc^DY22b#8uNSE^#{n6_>bq&t_cWx*>KX;H>63X8}7ICQ)h2u9({Et433ce;nvn zWpC{BO_jJ4Y#K3KnyqFI(<5nBvVaXM+53nD9SCo2HV^rE9pw0wYb%=lo!3@eBB8n@ z%)A}i!ZRPv!yNo4ZwyLA3JE|k2sBbm8df=VN}&|KnFOIv0H1`hnjN(QIv-sx1;bL& z3V-anHk!Gvlm9>TcV71pX{|aQp@c*`wg`n2Xl`!AC2Y>xEo#E$Nj1O}gO<16lb7oP3!tRPx7 z{+QH$Xt8iV+^OM&pZv~D8Sdv~xHD*Q;UXf9Q{nqFHAJ3y3S>*T@3j}C?6n#El!^Cp z@T20uWz~@dRG9EFy3EP6Zk?GR)YoNSNn+dh^y7@W4IY|`6dP-f%4%FzY}Ef+E|wQ? zWEU}V+pYTm(K+ZUJP|w$k2c2I>96O^_0{J1Y&YC(rReiLx1&~{qc);wjFk0+a68q zv?mY2#{J{=@eXVPJNH{SeQryt{)MF+bzF@zruM7N@v)woEx1+wV*-6)JzUcV+JoIC z{U}(YTRbI))tKblKMbZgsW9KyJ`f(K*H#lX_gf|@Jzp09w{M`&6FI>!n{a5Ym+XW2 zp;&EAck*sPmYh$nwg9p#Ull~k`Ae)1fAhjcf%=2X=Guj{ysQ~_(cVC{JNj0h-WQlE zwDB=_gec?fDf>K$`({&=<-~sDBxzR-yHD5?RIT~=xCNtvO~eC=$^rgHi28NTS!*7CPq zMeQsGRVav^@T)wn{bHUZzsesOH*mQ^<273Zi=>gc8c@(`rL*VA$B{}+>sAL{OWPoX zoVK05hKr3QHxDLDsg_%TwG=9&d89O53(yPzlDD#=rd*1K3kHtCfKrEF{Ay|K$O;w=O- z?h3|QzzYPJ7}XtHRu_uSvw}l+^{y>?%vas^T2avS`PvfIXoK@RJ;9XWlLz(=y^3=9 zPsdt}V9e)3WF$U3-L`11S^{1B{3zOvZGKI<`4DP&{?4X4(kI|^%7+Bv)!pdT?wP|ig46znE0!M@)Sl@!qLw$hf3@BfnuT4( z*YyH&5ZdT&ZEX{WwD(6}Ta9E?aB*i-MT19+{sW~=yx6q%<1$R{2h6+T7XP<%fszQ8 zcdq=IB!7-qJnv!(!nRra1-rM(mE_j5uhiQH&w@LP&x4!ZW}Sj4Ya5D573S152H~fT z?Xfx4c6IE=>g3Hds!EKY#8jI|XSm+9JS?FB2Rj@p-yvYxxe{(AHk_Tj^$8M}- zv}aVa|rv_n?KG zJH^$8;BbXunzB@61sHXDS)|NYdqa7+FxBL>C$rG)Q@Fwi%LlDf z>t$zt4l|D^BJ%0~P0cXQ!)wm0DY}taRvo`2MSfRP1v|Q+p(rvx6;-SADQ9(d+`wBC zm>n(NP1x5&n!4(0$;$GjLWElS(|-i3z_&S@M{d)KBoRW?7OB~duEE2%X0Ls}#Lai< zbq%v3Ck(hfTE`7cW3OIOMB}x|CEPSz9MRRAOPn_>A3ZD53~Pz4=qRnyBF&@!Td_bV z$--DU-4*F=2x{$Ot!)Tt?GMZErCR&F@_T*wriO2YuWYy}JiQ?tu4q^u9@}u6*6~N) z_36`5**Q)$T#NQ4x!HM+@z<5yz#lYkV^4m;L3yQ<>zbJOHzy%I6Sz-lMK6<`&D|~Ag=xgt@;fiQ&^Mzud`80+;gcJ#aXjf8mS`P6;3aCGe12r45nr9N&z-$by>P_V2BFro;~R z>D8k1p^q{Q_C_;UDS~#P-o80pq-{(VA*zD3L0@~{qwbTe7Mit>iv}ypfZ-RMykQqw zQvm=HR)kEv8pPMOs+QzRw+c3;aCd7gu)k(^XW(@u!Ar$eay3G(M)U^upKX`x?Juay zDgx9KyDZf>Z@ir6F6f0MGrqHWAA2>TWnn7}biJS~<-F779jWC&3XuXf?1Wzbxc$|B z#;!0hqc;NHKkDneecWqCv?tG8I<@M9s-?z2VpQa6g#C_zI~SO9ydei8!0md1b-uC) zm~%zB%kfS@Z4{g1wPBRqu_kY`8>LzDbk@ceaMiCAgvt zIIzusGoY;-RbddM9=&eAOYC%cy2@3g0JfgRQ~-}S)o%v&i|5MZOfmYPzMvyk9-Ro} z|J7f=)QCK0pBB|pHd%|%hM7D3W|JX(HRt)93SVSjn|O__xJ(H@barz%$iyp`epB6pf4wpxd6hrM-PA|pPpzXjCeW2$(?fX6Uh$r17bRczL z&_}eii(Coiy?V&K%d*Fkgyg-4Jg)R`&h_!!g(SdfK$17o;j09ZC_b-6b`-e6)T_~> zp8(>Rs#m;9ssjS<4@bL85jpIWBjejv)_pVVsp;l-c4QQrSJ0F)@rH!9##go!F5(fi z8H>90JV_AIK(Z0pofSs(DUlXk;`7yQqh5-prL%bFPhm}j56L&@R2$~q9--Cvh-m&k zSS??c5eb>!bL7p1j9Lw*F5jT`%#C$U)=aqW$f!{KyV6|H+-X;Y%(VyDTxO8hw}x6uM(c86v+s8@wZtwqW&sG{dK!& z3nR;f9cf!#>5@z^JFEg>Jkf!L%uC8SQ^XxK?=PcLy{)0_y6~8w>4qPd=ZymezJkaH z@O|C9S`jJmcj<9r*PZyU}~^o%JOn!<7rHZ{8z-r6J1hysJE$Z zsX9U@)zj86#uYgvT=~tS)(cmxh|M#E>k##Ai`Z_}xmeXKRarb}Ym<558-z10j~=gL#cUIPJR@N>f22y}) zB9mYC>>uo)YDc~#o6;~>3|gBb3Im}8|5CO}*+Z=Vyk8g@`(ksBXs%a#!(U}P&yf)s z&7a7r+PWrhYplpVqpQi=S!8=91J_u2t;x`hl&gu7%jsTY3H)8GNIEK@XB~%N`zUUu z&m+r$7i1^VAI!HgsLY_|yy=oB#NRciPNrON$xOi|;{}(DQ&V%c-j)QHB)}yyIj4w$ zy@W`spOH>X$^@6}L@n&LW?c={Ezi9D;m}*_KNsQMqLjW-bxztbd4I|IWIY~d5waT5 z2$3$7`MQtghPj8UPIWaK`ZwES&1{i9IvX@{8B}e%^-tWJcZu;XlhsMx^vY#7-bMtHaK>>Wtt;ld#XEBV(Zwp2}sRo1|2zs)grGKRT1 zkEcFT`~^9W&$2o>+%Ih`8$&+?I@ z<}pQ%@Uaq`#Y&9#=3z1PA>*wocSXiqwL@?w*w;=r-8Oi6Mi!nTut4Oh=qf=UO=XN( zeUoQd!L%(lxwjk3jQU1T_=B`0&22n@Vsg=bidoMngI%2RvA{ulnySsww1nywdQfyp zMWox^W@G9cs_fltWu46i6Q`{eC;S?GE%9H4bzIjq-)N41Upz5MU90jx=fxZU@YpAj z^FOzVJ<zt3swhmsueKkC1yzxo7{D!cfT_3j{LDTW1nib9* zgfW)>9}D_qY|QZZWx;x%)GHbV^x0)?hgXCzXgjxuzT61 zS-{+3L!}AT%P52Y6Qi%=AMja2_C@^(#hMp1$0HsheuL&fplcKTi1>7&I80|wZ4MaT zZ2Jt%@wo#dii{4@8=!r$%~&bez^cHAs_k2Web(kh-=qGE%t2evV;cDa(5LuO!4yk4)32MkW`A zFYij%R=We$B^)_&m$mSCVb8VpX?P!zC{AlXlM5$?<8gKk=HfD8(UccLQ<)H(lAxG& z@N!NpuW~LCJ5Fmmk_sbt9Un5kRu-y1F3cw20L2))+?>OIQ7tut9EAJCl>i;Kq&L+3 zor?^WxNuui)StOq`_1gu?nUHrU&GCj61{7$J%T^jK&Ygh3_#-l zdhFz$t#HQ~fv!D)u5H6dUc38gwyd9w*E%aRxkK&Wp)LA+c8hlH0tB*oXH$89_1IRj zyTk4$&rGMk)@ zvYW0+Klmyf;mD=);swu&o<82-Ta%JZ<*OCK_{?SV#o#A5BdR?s>BL#de@`}Xfg{?j zvWX)i496*d=aAVCq|=VSDjF6vYOLBv%fuOuBvM-YN-=K#muqG^okGWA+VKvig~X&u zfE(f`37I)%zMh<6uZfqQ92S9}dTqHJDt$0WB9*tfL3T@Ut+oG-Z_)#O;YLYVUVr5F za}`od=PK8=Up=3HIQ_}Vyd9%g4d}5uTzV{mclp{r(vvHF;+amC@<|~R$`}`z_gH@g zf!S=zp(hhqw>jwzeHj&llio0G*YPyRn#zR}_W8Rw{j&)hPm^WD&p&JH5jyiyFg9-= zcAfp=fik20yvj|It6Z+8a;0_rOf|u72Hiz(6Y}0zCRDi*svJPzIngi?=`$oVV<%zE z5PLiGRZ8>6Lgqz){WWk2-ia51OLhw`;Z)O}W@0SPb}qq8%6tGeAz4YYxuC4MzFe?L z6ZvI*V3LdYk48#72NgQu9&|EM&`CLr##ti0d#!ey2_5F-r)pCpW2fovE7`r&S%T_E zpK(uhwRCo*T-9`L+>Wv}>8S8ACxpzA*m_wDP{8-nRY^CyJ4=Gm!NSO|oWlJ> zqXg+}^eoS;D>@Z44a$3DU2O@*j54Ks7QsPGUp{pBss}x2mK_Dm-=f_`_Ny8DoSH}F zk_>OAW=+lIoc-`@GNqEvqI7=$kyO`-jWZr7_Nj@KE5Dk^U#W?7HsYuFwB6FbA^i8A zB3^3PQ;E(K4M|M@i~mWAkeNe=Bos1-%W)jYvUib_dW&2(bV_FQN%Z;7jEag$jl3+v zPEAs?pX7XVFW)$0_6cK_oSsAKKh;;}GN-BZTsk$XF1s|UOQXU6Qf2U%F8hYI!)J!C7R!?c>Q|h@vJ(~lUsk5D z{<7k>!&hq^?}MT<2r&zAsUm_!j34QX52G=f!a25b){^Z#>}>1Rzh`f`Wf`l)&D8<;26_n-}D4z;~Xi7{F~yb zXiepG&uKTd`IvT%Y`ZQ0?RE=4tKA%5#H@WqS)X4HXlt>BA4jy6Xfl$H4`khq<+#zF z@|~;%_wzPL^K?9uFUh#k&Pw~w>TBKp&ReQMvf`nQije_L8``X&tXA_T@~PJTzA!R% zH^Q&J#g(tKGWjaMAql%$0y6YhC;@{nva*q{>l2i|87b?1UstW7?~P*Ytc=XCzVR+V z)npb1(#f#GWMT$|=SV%7@_JcwJW%e_*6!FS6v^8ALW;n%$U5D8H$M9h(HHW3ZK<<$ zE$}WfRc`H}x>ZA z{e0>?!|7M+5X+w6C3sD!3%B=Lm!09eep}OKE^v7ALHzBa4$Z_ zG8}4nxOaSv;nt;Np8D-e7n-{uu0%fdVQtOdiAqH|8#mW~95RpOIvXb;(;*mh(IAa% zhLS39*L()J!UrX)0$@)|}WXzn#%uwH*h9WXyX&>5-DcqQxY??y%hQAXLb zRV4$P^TOkY*D<6)vTKih1K9F!wS5ZU|1B1+_w}OlzFE}7 zS(XZ=RaV7#Ga8Q-n+Hk=Ji=Cn%LzQDwsb7;1iv(OEB~iqynBRK>#d7FPAR<{OsH_8 z&E3(Th`#g_|1i~Dj|Gp0Hm+pDwJudPZ1cA!?22-2#9IQ;-9QAwvg>ed_isiuJDon|X-zSnwb2 zn7fOhwrSnYw827QnD}qOs4PkjjMFnP&Jq~)42&~A7seBZV0`2@V1z4HKpLL~WzJg4 zQCDB8JEx_2k#L9#Apf<$_VO88hh+0JqHEG)qkco?0xXBGM9#AwWUG(y@WC;?TqpL| zs#k5OsFsI=(XEK7*Z7*vkAvm`$+J2VGM)+-1moXI)ubfxd~vY;Z=?za>Y#afd9eQS zvhYpXTGFv@C!t(0c6qs!I!{afGu*uQ#<{>bcY|iO)I| z9V}ROUi7FpJXLR7Im3lR27w}@_0F%#A!ex;j8va(3IJOBe71Np#2-AxXcR@2G#x37 z9>qA0$p|@u&Pj5>y>Lpv5YYe>{-2&}?VEV!v`{SI73i=`Pq>r+E=*O{Zi+uzW|E-g zZ!$^ZXJLNiuf2wOQj2!@JW1?4r#7~rGf&_dOl(;^Lqw*UA68j*ey~OX z^XE+uAy%hb52>ov^gL#OBtzy(pR$x=w-bxQV(E~EcYg}X7{4T?qOXGH+k^qhT)hW( z%3OuadF7${d1YGr1Kh#zjAz2&(?YR%YQnJbxx;uG6h&4MBTNQ{;WMVUUs`^tU8={M z)Rd8;@MCXyuD^E4j7YU;k7^`#Y_Y%d$_kDeaI9K6sl(x5C8(`AqCT@<@R( zT8059EE;FnPGfRc@+$3b$acuYpBgf&Ah6l!foFTdr*g)iB#n||1{Eu0#AcUS{m%(I z6fU&)0+djTS_v`}8xTexg@=m80TX*u&2A!-L_!w-Nm!A(xt{O{5hJsrVGx^>5}|Wc z4tRugaugXQks0M>otv(*J3GtlJdWGz5qcy%`VidWUGY-gEoG6jq}kXlV_RdlKyPmu zZ^Ul##%{s2?v|;sTdK9S9@Hu2@jKnIRb!oH2uaSG)U0nT6dEwcL+{S*YZ?ppNv_6X zYYvZ9xQkszd<{5yjz=C(=P_*I+r*^Vzj<;>?HH|NEhSKJx@%cV;!#8;7;2ru@C}}} z+Or^9scv8ADnJwG(QTFvk10x>n`G9x-^IN&fdP9tAt{bt-D8iK+Vt3akpfEMH@eMQ zf_x;Uz9OZTG-1FW<>MC<*w{`ZUO0$3!dE*zPwTi!KIm&I6Ps6SY$>C%l%|(@V@ny8 zrBiV@On$&x08*%^11Xkx)|A;xj~*cJL!Xh43bV;$O`ay>F{iw>Zn~kxRe%jlSC@?G z>C(hmRDkEt=d|(%TA}Nmb54@VlD%pH;(Q^#DBUYghSuD_i0$V~9lzSgq`K%zd?b#yQekC9bVyV(s@^2LEF$LbYDSw)Uy7aIYn_8{ zBiiY=@E7UiE0_5n@)NlbgSA_P=Q-t|HluzH8{a%+?zKm2YsaXC0iTYBi#Hw#1?PPM z=_x??ic2jY$ajZNG8a~3C_T=)6=2Mxv2yE^Te;{XGlGgy%U%DOJ`0!QHRralr#LcC z`>ur5h3_Qk+3xU#Vok4-Ka=E7DY@e!tK*k>lH2)aqww^)@{LI*xWwu0eKqRVneSeu$3@xOPk+gh*g`%OPk?>nw0%>8j=NP zw`VT8tdjxTF5M_H4G*n5_{~LaLw*xp8d<>rQMt!jdxRnFSIj+@E18NWA-;H~!Am$( zB-5-Z7zPV41Vjft3UG{#+pH#nvTcP6zAs0F3fsL?;C@iqKvh)zO(Hymm5+?DqB-NFt;HGXCF`xTK|j%k6|Orj zM^Xd3AhFdafN^WeEO^GNa{R>W>UV~xhh!knaz25@I?j}Tt}TM@iv(&Jt$>Hy85T#W)wayx~io(JgT;7MubU=$_C`L zQ(Vhse__`>4H%8MM1;=~AZr0qwwz~Zy8!|wl5Lg?jBB5b2i^)cx5xUY!7p1Jp9S|2 zZBvYv?6WF0<+9#peQA{ntvt-4P;34qXUzlP$*gLJ>zE{qPWGB}`%UKBS$RYB5PYC~ z+&KQF%hhnLlO$4Wf0dzWn72HjwNF4>*r03e-;&>^@SFz!vND`$@47RFxG+3dTyEu%t%fC$EflNMy*Qfn>B=$K53<*z zhw~zZ6tp?HG5E=$1pP~KDlLpzxS+RjDk^@%9c!#MVi$RwXjUN*d6A-;?#{-kXb$vG z9#=(*b4vK!eT~)N3HCV&-Wom07~}#sKcR-n9|~mO)b0{71pnUK@$daM{=MJ8zjr?V zy{F*cJEma;{{8?$8KtxQCKrW#Z(pV8)8ErPeRfIPc1@pNDM-|Ql1hX!*(Y%!zR-3V z7mASK9bL`FbIGyFjHL&Mk+e@5d;2AXPdJCE)y^5oZc!+m!u>UlxtV(+$hp_KuhX94 z9y?X>@^i!|y&BeqbAp`E7Hio&V1m|75U#OWt#lBPIB3nGNn!OCZi+4$%cfq!Id{<| zURQKUCI72k)4F?`#=Cl(ro#THiMMyX~lx|7c#P9->GheCgXwU4lVI{tgS(w;*AG~P}>@-6*WtX5gmbV zV3_FhRC-?yr@uqm6X@`oHmMf{3eIzpvDQ`J%JQ#oU9X%trz>WuRfvHwXxNf6!po52IdLp4mHJ;@9FgRcs-@i{wr+%)+HB(+*()7;|h2NAOP+ zKiG2X4>x21xe7p{q;C<&BGd`rH=W_WmM?-J}Z6?A70nTFcs8CuiM6N z^MkF?>vn*QuG>r2(pUNamfUcdpD;VZM)jZ7~i9cQ|A=JRCSD{j_R*nHT#UhJ*jaY zzoP_LCRWvBzXZ|EVLk;y>*vUghUr7a&S50Y+7FI5?#xM zM$N>lsomJKjkjlCED#Y%AQUKh$#|EGvg?;D{fGVa{o#BO75kHny2}}d9J`iCH7Gc6 z&%H<;OR*)Lc;-}`&kgd9#n*IGEJ!V-b+xkeyD?c4CYl))Ha`nbb{b7%CS*k3B#eRR zh3@bx$`C#>1g60L^*8$k?%i;={VBW0FmFUvvD6b?Q9uOQb22W`1Oog0_i<^H!X(II zNWi#njeNMKHtuqDo2$ygx2>tYm&@>tYihqMzgMoQ<@@e%^O{sjSD8#G5+V?%0+cUZ^M)O}`&br}zG7N6r|&)RRBd3z^x zRO@)057nBvyKo^-4AX6TAb?n^3nxV6eq2Z%!X4llU1W*W6tS^BDY^~GFBPT^S$PA8NRuJj_*p10Jv8~!5ghAL#V&P+c~jeAO<;fdg>Raac~qr2VzM?e{yOn;0;C0vvmcMqT4 z=gg4ct#NmOw`6Jf;d+vn&@6DXT2Kw-C4JnQg$FwLWXJ~gS$2yM48h`N^R=M4Po*(E z9E_gf3igTTB`}FMaf}nBdp*8s@3dVwDWdt>-|?-T?5WB2SQ8%BvDf6-WL>Dk<)5O1W&R+2NZu&{ZUi z+V6p)!Ao3iu?V+)T}Af$@>rIOWD_e2#!eC7f~kTErLZCMU?Jb7y1Q^Sxib7w+u=!( z>h>P8Dbec4+Dkxfyta#LcJqKv^b&nlhNgqoNA%`jDYlMOk?2OH`S2`0ig;*$Wt4MpM-+F2BP&ct{ixr8hB7n8WMc>zLUt;xuR;}L>*pu%4D8_g9 z7?2ZW`aFU7e8vF`0^!EqKH7*CR#TXtG5qlD&-hk8`)7U~lX*tjl(moN;D&VihWBxM zF?+jCu&1;gnW?n4njh;3&QSfL4<}p>%swFMFNDvovi9APy$pfld9t!83u_7OpH91U zFLuvv*TR+hrD#`JHAg_Rtdm|5xcg+i?-Cs;$^*i zr65p2wZr&WC?mRw!#3P^zjc*V8ea|91y%z~NW&MYhK8(24((7eNu~d~hAAwx$N`2} zq8MexJxjb&>0Qn{qHc2D)k=h;q9D-rOZme374Prk<`TJiM%|dDUz3};QqnBFfNLtR zP3qh~pIpbz5&9)|rqAGCE@hlx6?RyXtJEBXf%ySXj#(3qjVhbtEo0(_by4X>;Hh7U zcvuC=mt@(Q^&zvc&Z8 zkwp+My+*Dd<63FBkjUgq#l!rZ^^ks;k#Q#e^jk8J+pMoHkQKDeI`o0_yZkDd&TZDY z5O4W?5IaUjWyYG~jF@XmSzVcWN}J#u>BB)S;TEakR90g(k01v3{{uhu+rp!)s#5BT zO)TemrYdI-lzzVrm`BNLv-Ezhjp&p${J5+^usY8QrK;$Zh^XxD@56_bPxU8M> zEIQ>)xyke!o~m#OF3<7Oqt}p?b}qEZ83zr`6nmE7NwpKz*j$JvEL~9UQKp|@L}$Lu zSjw(_bji@$__$wvL)H2iwMqp^Q)*80iOWl}U$T9{2ka<*ljj0p<{Mk6Bp7Yv1~F(_ zQy1a=TDakcVpm@HtPQdmQ{z7RPsL0WZ7AaQg)<%6w{aXw7(H&}S!d%cu_0dypNI;a zdYyUT$VhP3D8;KG(M2Y7o@8Bc`B2*B-pe4>X{i(Ulu%WosjI-Fce+s*fr{TWFi3&P zP-nbE$pR@kiAL<_o=^VAOb7mB@xi6JDM}~dUWw;H5|?I`>Gn;Wf1Y7sr5#*m(>!TP z2fjE>DT#RDPZUC~*=;p_UDhKzOgIq9h#^XVm^=9-m+0IYDwI%7gh zfh9U)iWafwcl?X;gWMl5|B4?ZsWO!#Bqz}Q6-P)Zm2sfV*MECb#=}u$ z&|^Fty?8k4Gd2&oIBNLx$%6%1|Heo&4s~5)LRh~;vHWwUAQ z%1WaU2~33}uyvVr?(@PY%Ay7<%e?2f2~HdK7F~Tc4Z=c5Djo0ON}# zKiaSGyzJ(39%<{`t-x`7YkeNBRMAA9WGA7#JMw2Cfjk-khP@pH1s!h6x3R&J|l% zrRy30ch~cfQ;*Y+nDj$d!YMh_=Qv2^_-_i?=?{;velx;>bUo#A`{`5OpOSqi){Ocf zuurrNNC{rWeTrT|MFYeF-WZw(=e=kl_A4!fXcS_BohTw`taJs9#RB_dbNR6Jy~`mC zrqt)*?*3NZaTmK!d_0}!odR|IB3$qJDn7rmHP-pG^n+V2dj!qJo6FVP=p&ML+hv^& z!vJtQfeRq!(`s|Mbw3XwLFhPGxH1ak=Rv)^@TnHO4fSoa*1{|E33|p%e|_}9qR;%7 zs>b;McX&_b&7cY?kUj<8RI9Z|w8Z^ZtJG&w*bLrmT|RWPzzPlBEVeEjy1Cw(HgscH zQ-*F@tn#6o6;?_1Ce|ih{+Ka#nu<(NaoO?uNhyq)VLp^_ApETO^Obf`=r{5md%3ZXadDTz)q7F(0|mv)hxZ6uOtJA zwVMw>7=;Gn=@lFM8M_TEDVOywvY}bJSUyw5Ba)5jQ9edUx|gr)?UFU+0jKnFX6aWP zh@+~#9ri22H1{Gr^SSu`h+^tLfKQUIgXv`?M0yzVMH>y%nBh(6|6*rcCRk^w3in9| zV4Vk3;T85jn5F%^SKuG700=M1fqc4x{AcooDdiO8HtPjYeh&tbH1m6`mwCWDAite2 z>Dv~yqP7X-+pJLz?LRMqzBan~|{U*WX>sc~P1 z-G}~PJ#5_1=3}5gL7-RTezH><=%3+Bpm+8|dfdfloX_84B4ym`f$uYh{Fr{2rAwtM zy8nSJoe9=gg)-djQt{{D%=751^%3923ZJ}+RWq1! z+;^-?Wz#Ul#Z(7J?Xr^@Zr|a*&C>74_w;p?^)%(9rMGaOk$Q6XS5_d#GInj2ZiXvJlyox+XfKHPK*$_5wUOB(G-{Wbs5GIDgVn`DN^%aHBF_a6@ zEj{Hn`Z8|)F15-}NR7L5Cv($p-Hq2Y`n*e2)@w z7Z{QQNL+T96r5e(J(5zoWGiGIm}A~^)cg8qk=&SRkUVTbpM52{l*^j zn0vMM0}3(k76jXq6epcv{o7i*#0i-ZjF1lvw7oVOz+Pb*J6)B03=2GL9GdvEu&^n&rqtv+O9iqj*EE0$>ctTFBV)ezx_1AGI$dAAS^p~7v z^60mVJ+!vn>TsT(pbRfONR6AEtuwM1Y)40ba_^B;@a}d8vgqalfw)7m!_(QoLKLB9 z_XZ!W)6XjUxdXMxoV%Y^!{I0vT7)BAAj@X44DV3L3RsHz_1yXa5ocreze!KXbEmHF z=2|A}URvC9MX_t6H0P*Bs&;j46;HQ4TZ1(_=iL2(YSxZr<@T2dI<2O&8_FpXiWhph zrvDT9vC5sj7WQI_=-xH`uSg|Aq2zuO5B|JeWcAdPzovixIP7;gjg*kScxeqS zAa%wICrOKFd*b63*U~RxgRG0wEsv+=mv>KVx!{rSNYKI_=vivq21d^=N#Bg3p)^{} zlCfjgI(=;6gmF%EA;=?Mnz%|DOw#nPzB2B1*e-V;hbnGGJ~nUDqacC zhIr{Gi==Na(Wwu)Qb+C3&sVv&j)0=2V<*zFY5OjnJmQZB%)M$kUM~PC4(a79GNZ}5 z7MBkAo7*d3{tKrr5G*^h1KrSuQvmuy;}_zNQYN}82Y2C+eJ<#DlTs#@2reuGm!-lZ zQsch+Jk@e)lCt^73u~2vXlXtfIIT3UGKw@3`HoA6kD!w-1Z8mQXJ|81@0PG4Q1t?SveUN&4S8Bv+9l4gF)va62n@S2+{$~FJT zW}mr(qe7#vxy@bCt$7t?r2O&kGPg#z6jXTRnmp~~^62+e6max9wgtgnTgobM_wx5! zHp{4(`jo4QYR$TdhSaGjrPd;5wNK^3v&Zo09|^&cKgz9?*jkR3EC*ELKYI#6W;K#g+W`^oRNe*e=)SeTuQkrCj)>PF;xv$9{Sm zpV$j|`WuCpz&V1RmkAl(;*S+xfYO@NamXH%(Ed-XpklqN z%vBCz^i1xDHWYwCM{!)+)S4}t8@IdHy++B-bWTWG_nU=B(Y02LXc!S-rBU5`-174_ zKZ?UCTZoSI?Mmz0q6-&yQZf-`(XhzCCopf~xW)^GJJ7FZX_8<#Cr6wUR|>Mba2_b8 zhC|u{2XTa6f-zzzQfj~TT`a;l``5fOQ(UYhg+gE_${BX_N_#a{#hqqfV$h?j)vB%S zH_W`&x|5AN$~v371M!R8zRo)mor`+xkzB}Wnw^U{k;qTytCb!j&`k>6w`pjn**J>x zOqmhUVj$Zy2-c70DJF7k?V|nSD-r0AJ|gOgPteevpsfp7lY7%|n)`>`!c>A(_io26 ztc}^qjWoqIY*E&Cs_To>^`T= zMP>nx(>dkNb;@1&+2zc_zW>Gea=>41nUCRvXzL>=;%Bz?J*Uj4+S=rld-|AiYCWu; zFVt1GdGdNLRk$g1&W}@N!m3tD%LO-@iGhSST(kjk4#NBx2}9IYv(I>}fJ?+ZmwmE& z(w^X+k->)t$58cVa)167Gr@Xtd@`}b8}aKO$Ng|WpK+q!K9^u zz%u{ms6QU&V$s7|mQ6a}&9FZInm!*)_gOo01&hCM@RCfw zQT^rg`)>NZT&w(0t2{!lB{4R=zR(Qp<@svRjQE5%KN#Kr2JlAuqW$^wITqNfIQ_u# z^k@X`cJ{^3nGaR_HfuVhfiWnZHGB+c>QCu0*qbv3FQc?jWAGC$vSV-`_9GdC<%~g* zjKQYu&KOAFvSYwNtlFO)2*D*~xw-w|H)~QtO?(V^T%iSiyZLBSC{$C z*9H=v@VG$xJ1fiLm${k8DeptkYP#Y;;qv|POXIO*rDI<(v0 z{uizNw*nGhjMSq4%4PiGBCDAXgXZQ9uEmVXyCxy$ORCjex#sY87+ZC`WS`$0;Lyxuu@qpJ6Kb@B zUJm;4Iq!U0G3L7VU_$nOtK!j0`oz=u9DLGa?G=wPgli6~Ln$wl!W-qXY8UNIHTO;a z6XyoY7vYgawfehy;dusjS+X&G?c2j1ZKHLn-0VskRWC+%z{FI*z)JzB+*E&OyK0>- zhDk*NYh0>bc7E(SH7q<4Ac3rpaJ)jv%M`F?(kIxN6BMBdkDTdZ;v?tyryV7AoPCn7 z_Gt&0ljTY%U8Km@PDM}#H$P50`m<%ckv+sY)B_UDy2Cn~{T_YelR*1h&f*%iv~+`) zudK1^#d|`)eI2Nu9!m2OEM8o#`cM<1wa!Yq&N<+moeJhtypwPTY+J@{g|k1oy4l&F z>@K0XMixhk-@2TYXyDA5*64eo2D@PU9 zvqtws_m`a~9tD{f#fkm-=@*`1FGeQz=cQj140}ax^R!v2Nqsj()3bHpiDoUgm-HsZg3I=-0vNw4HJ>Kk%+sx1I_Y2bd{q*#HN9&S^ z!1YjtC*M9pU3iZ=_j!_uh8NyXoO`zonwI;&$a-RnF;Hzfb7nB00`_A3GXiC&wJeq&b9BsTu?-msef=9k zuyn6JxjWjQ7t>W?W#|eJ*pOR%ewo?0IQ?0ps>d)-Fk&q&)^ni#8V;IoE+Yj!qFriS z@9$(lxz|09$!KXCYl`GrhLP)Hxt8(edZb+EIoBm}?dH%{o{uu!(f#@1YKcTRRsM_? z_lQbkO^M)C`&9X+ls{FY$+gP$Xt^$B=+;b5Jxp+bj0$bG#74+)>e#9LQx*-OJ0Z6Y4~an#At1ORQpb zbDFc&lrB>ETlPK*QT|?<&4S#5lHg|a9ik55tk7;m-kBW24qty3DkO0~XT{u}B!Xd| zjAX4MjMiIRn(t=%0o{Rt2JvQnM&nE`K_pf=ZHkTL@m*rd!r zC2X!4m>zoi2>3`g8wA0F zdI{fpFacU9i&QWfqw>2!8%VCC(ED2~an__pHLdxRb~<%l5CPjG|kfjr%X8hGE~^C=5bUH^mak0=^4X zl&yI!1!`8;xWiO~!%kZmJp^c5pi!o5wpb0oJsISyS5-H8-H+eRq8`X+4Tj{eAswJ=-zqHkR2WF$wVOUoO= zUqLa#&JhY;ksOGpxI#WZ$oSWq+Yaqovt>1*xs&@Re_XNyl3U$2^YPj6Lg6U`318T& za-Q3#^%g!L4Y~pp&kmdWReGJ zUs^ll)&2{4EL$%<_TnloJCMK5aMmR5C?9f%FlzcmWylw@R5o#*OhAmM5A)H)s+pFpcM)&Uzu~F;0!zXWk|Gh1n{~9jd{K?)#NB8Ez<&k1s6TC#BMBWU> z3&z-^+Ui_d`>$zT9AkO>o;o8O#G~EQ!PDq#nsRb6s_<8S=~%et#7B+%0>C0yXMxf# z+X7q%({P>iq4sTes}@eQYJ0m`Tmlr)F#VCY6i^<33VYK4eQ2LR4AvODr|Cb>l?N}M zen{u>qGmj|HpzJIW*F6wqAG;%ghRk}zkoRGU35!p{|U&WW=m_`NU(z75u7uK=7_wT z?Bp)`+No*==%r`?q@%BdChrUGvYYGoG;577*KC;+FIW&_NJmozivD!*4}w)Yja^5A z^?S6A02SdW(jp1Ms#w$e_Z#^=!T4C8ME*^bnRqS{iR4a2kg1SZz&EIzGa67!7Lzsx z*AY4!c|U0GO4>37G8etWIt7rxqP0s`)169inSttEl?)+g>i%y#6$wi!QR!3FCT5U6 z9ZdJh9`~WH<}i|-LjWh}erx0}syCyhH(L8w!R?tIy^}nXJDC&*{&1Os{Zpfffr-tP z*4uoR9jhhHajT5v{!Y^AeB5mA(t?A^yY2n>?2^zDoJ;9}23HZy(`W^72%RT<-A5FGK%8i5`+aC7dDq_XA+e4I#8(mdf!ea)Lf zJM8@4{PTkGh?`7FB#Yl9Hsy!ZAoyz+Rz|Q*ZnLiVu}Tg74~#odXE6G$7nNbMkF zxt#mh8twVp${qH_e&)5C!q8E6>~;c%tv8u7mB2WRHu~aJ*O++YMvirnGnB{*Yrhw) ze<6H4XM9R(hs`tW{P?#})17JOAJvJXa7G9yCi)S8%8Woa?p;D^)f})j$mdKMY~px2%66uRsHyFuCJoL zW-~$9k7o3A&T{LWb;g>*7Gr$-bYuOFL-XEv^heKmnt{i&47-$g;V&|w9MUg7ab^bZc5#{??r3NVF%iE!MdIFsb-0U0nULL!V zGcP%oBDTt_OPoSW#>f>k51PMJ_AeECTC6KR1E1`j&9OQCnBJ}Ue7808A|Z;uQIfAe z9*{8l5KKXJ^!5th*?x0pdTU|smw0@38*ZthUGfr2Fc0rzIl=88Y6#) zB*yYt*BEN^6-o}=^ZjhH`DMYsptaW)cx@vGGwUnlf4vEjxE!Yl3{N*x@0| z99;ein1L1o6`cHd!}~rz?UYX*#^4f*NW4H-l0=a(HQFVcqus^E51~QJaYnsIjfryU zO{a_wMwjekJ$L6~sapJXy*APFZZ(eRRJ zf<_}64Qg;eW?)9n$V9M81)ubylvZ0QnE|X&1CvyS<5X^|)jn*!wY_TVt@fb;Dozqe z!aD(#AQb|(dWPczQAq%0e&4mvOcD^iy`SIjuU|f&$vJ1AefDGRwbx#I?e(agF1w76 zGj+$?x?`7Kehg9(!0i|-;smD8PV=4ZBKgqj*{?GQQ?ihdg`hTm32|CmRS~+;XI!1_ zWn*@4j<>6$c~a(RZ>0N<#lu#OthcW7c9{)FoknAWInvRVaeWr}?ZdzY-|S=%%vKq) zdNMffYCKE^U&f?tuxMUZcrbz1iFp~jj$o_I!3^_tSTWpX{zi`0k#Y3eoUlAB0`RbV zX}{lT{Fc+$KB(QD0+nK0``i8*+ZaMYZR1TrZt>LUF>jj;;eu87f!BRdS|Otx)IO_l zPEcF$7@xKkK1Z`cNWiD?JP^wp0&?%P(RzhHh1QM?YlP%ie&9Tuql3=HAOdA>GK&Pv zC!sHxn>zay_XB*%jvV&`wv8FuinUlB^3krq>_B$4@v+x1L&GFqFm}tQW5O62D*-@s zN7I}ZUuLob26pV|Fcx~F#fEOSH(QiR>f`qZ@BzWTn=wrrW2$mP0}y}_8nq^qy*B@m zmD`BvNFk;i{BJeK{S>292kXfm%b`0unBqTqKw->ReldVA#9(r+*N!G8;; zBy{zHVMOt{va3V22>({=mtXnS^c3rnFPL`2A#k?t0jTqaLLI@2;G`5sl4GAh z3SuT(Bi)}bzRGQ9Uvinx-Mu7lg_w>axa?X!>3F&%Rf^OHu|(r#n;=}K`9GY|T34Px zVACIvP0?CAZv{&9w6iajeF1rIUo>U128EI-Dyw`?sPh-FwT~@a+I3{HZVU;$(!x2`*m)3$DbCCF_H{ z-eFpUdRebveH`~Maql^VoVLnrfp6X%&T*a$j-9ahH`dRTD3}J4w34JHhE*n z2hBi+8EIU@`DhQnoYGI7RxOsoXr4&0A#o%9pju61Hz809mX@VB-!BomdrB1_d=HGK zI6)mI>-N)h_GK}LQDY@RXQMMNwAP91$<83}Yk4Ia_&ZXoSmcN|lppiH9O=#yug8aR z!`Pj@4k#J%1y_9^>57wvsy6cY$AlpS<;)b#T zjbj=~tVVy(5lC*riOQR(wR~Rf%7`4wbZnCYjsC}oHc4SBPXQEzlc=xc~CBIf1gGd6` zR_NmpjyhYbGt`YZp2NG~>5;@xt?sY(yHJft1IMRFf{7#JAdj+Ou#xe=`M`>8_bi7+ zlIaxWUvah3WG>-sLE(4$V{*yIY)*u;Nqv9fH$#pvcju=+_`lSa#Je1>hEo{xfBABd zvTRcZAR)!eh`Q6sYw)M%*lTdlzOV>iqY$@LBy&&Y?tp+F=@yAgXG70h zdL;1$2QZhhdubP!0dtirSVA`nKeXXGyY#GRKOEU;KY5Pws&20cIgHyc#FG08ee7dZ zlpelW=`f+I)Vknuu`fSOyzb@)jrB@D()^G$X4M6J8=ZWinBVk}!g)+~j|xaFUtvA- zLFiupa(wn44oz<9N6F%fP#OhB%vFOdP2`M*?We6!B8&k-bcl7adHXqv=noo8=I}#O z2<=9}U}ds!-5*5cfMcvMkU2#QgS2ohpJzlDUI+uD&RcChmFCJbTWj;YV(3V7;wp;J zPeHGh?J{n?mBS8JKn6|dlvYuTCr0~{!~kymRX-?`5TTpQ zeJZZo^+i788+qQPN7d+@CwhO#{!}{vt1$Bn=GJNSYJ>2bNIFHB5*+(iH6DYN-{Rks zqP^IUIFgB9s9P`~YmN_3q)Wc#Gp=!=^pp9ca<4nF_*}2i%qLhpuR*|=A%xu6D6>ug zQEdLPSOBZ6tBUm5_>FQW=4-yH1(~88N{o1q%bLjv6baCwyv^~m_0KKc|c;6V4POZ)gx=inu-&fII4m{~^m369ZgmmJLKjajG-Q;yMV zmvpN{J7(e0p^^y6QZWnVWJFf;S)7cB?gj%KE;KI%VNxb)FQ27cG!eTNr_vEy-})ldKFY@D99tSDeZAgw=%UG$f6+4o(uwP3*HXmYfkKsIv zJ8qNI^`p%2Z-m8UCJO@qiS2v9#MU#Vmudc@jOsTdq877){7np|Zsg^f-v{?;(98C- zgZe6xg)jV$L{-JHqAF4AN3vR}(6=H9VqY?T(QVpy(%#Ja~1*Qsaf_(Coix6C4Hh8}SzLzDS`Jmfvx zFEcdma6ea=0Dha-GZy<06r+o)Hyr85AOwuOR{R;qmHDEty=+Cl<-T_8 zQgNBmY(oaXKPhgur0KRk)m=r%Jcsyr-#3ubRcnRc$KxIwJ# z8@k!@3`cT34mp!=FQXr4^l{uVpf@#ejq-akS@@p-Qf%kZw*!GP7qEYCO%_H-rO(AEF0rNCTLvE%&XK}B)+IPN4qqtu zF8oDE5}pk9mMN?=oWGn1c=(dQ9@+g`JfdWtMC=x6c14amwE9bU`Whs(&repv#buZe zX9*6naW+6kre&V_F6*q>PKkfZw6m-y%Zl{Lj}U9y4h+nVjUOuwG4kAyhR^`B>sopl z!NgGw%F<&Q%+C3Edtf@)YQ<^`E8BDR*IQO(e2z!(c=oQ?eVO62mnM}iAFH|3bs;$P zQud5UC+mnzD^UIRCUeL}dWilBGpt9eko#6M-XUFwaY~g@XzK#bJn{R;B3I^*hCm05 zP2%|1T(&a}Fjc&&iFvFZ(zjInw z>q2DwTUPkxLo1B3^NO@E$4-MG1kLqAy~ zuwna}MdHBVQ!Em1s6;!kE!G?Mbi0q~CQ)r|+!EX<91WQP#8A**@!M#V+`4TF8iSI~ zt5_D3O_5^*=kLJplh`7af{<*V6fx6hqq&_|tH+%0%8ZOb0FtAA^|;b4x9c!Qd=9}z zj1qG;ktK;^3{{cLEAl1tWxZi%wAV&Gp^rUf{e(Ha(?!(Jm{pO?yl zTI#EsUna^g*A$pjH^Ij)uVGtIQ^1dKCpE>1fmG$Ix+FY3ICg$f*xx66aVon~dNi-) zNhc&t05+W52=U^oW0MNt(kiUSy|7w7kqRKwQ4FWC z1zu)=`5-P7^x63A31cF4^RGluZa#Y^l%cW+elf#Zf?H$!As<@c^;OlV_T!J^A!ent zpOLuSTq{%b-aN5Evg0MbDa~MWB&~qz!%-EhR`iorJf>Eg1wzx55A9-mh4p-S zi!IC)l;x{n@A*2|@7Qn(*cStP7QaivH+%{BPp0xKB~-JWr!RH(6u@s!0iRei*5gXN zB0ZOz3c9WaqH?>j#b*8QV5eh`!H{I(PPkphpzI9B;5q&o8HqYom^}=hKEvQjHBBU6 zRi|p$DMrDa9tG8?6f#s8TVzlmcQPX8>xDg|areoifpGO?F*kc4=A5h-ef2PH&vyuT zuxJyj7&d_T&@9B)LF`uXg!OHx3+H<~fxM`dM6bkdTBuoPFuH`0QfxSwun>gl`kWTO ze!&EYzHj-GYs}|Zzr;rY7&}f(nbk(eY@itBd5U6|bRsm@-AhcZ?rjCRTyswg!zQei z`&N?!X0_W8+jOJN)ZkO)%P=R%WH21ovJ;B1d7)hMS0@$`Q6(?w3`91w4uwtPIR%Zw zP~mC8@-Cs44abpSH0y9c1h#}%!9uISUp3ApZkrlmFlsXMoVq0 z-Af^rqoh{p&GFD6dTkc=v|>;ABZ9FAZ=6XQJG&Syx+a!)FlcnKAj}9F`{b*jUf!Zd z{dzSAiO7BlB!l1t|AoZQXy+kN{(3dy3&(U$kT#p;=L^xsy|3ZdQ9zn;ZM3wa+VP(7 z8$rSXzg$Tu$6GVZmCYwMs#cyAbZL~d=pGVe^4feF#PbC0#V^Sbo;~d(IYL_I-D@Wa zKd=R9@sY~IctHZAq<6{n1iUyu+@)lH0rr571Gt3H-R6Sg*hJLyzs7ww(wz-3!Kq}te8ZLDV~g~K?j%$6T@0N3jB_Ky zEJR~st5&ZNckC76a<8#7re~YK?-Gk%J(^>F6F(l}%>m|Oq8{_2hB+0sd~$*HyJ=dB4lrq@)E%AJilw!#RVL4f^!!Rq!9q%JkT?rEwTV zb_*PLXTYfa_H34EvCpU%@8s16ljw;4a;A$W6qCW-9y(`5)`b_38@+IVuC0yh+LKN5 z3j`_Fs)@_^w1oHgR%Cf=yRQtNg_A3Md$ffLs||6%2n8bNr&O4DlG44k=EXwGYr97; z%nPJSdp>i%!@HtcFW)I73@^w;?ZJpxe1D6upA~$b+|8&S_JLey1xpV2ki*RtK?_?o zY?lQH2x3-?bYiTY7e14yVavr~1A4P5%MPEh!KyNE29JUF&@aEYr2|&sm*4osc^+q$ zbVL|ekNFm(FZxJm|M@%Xu{n`Nn198@G(iBqK`e;pKO(U0VAqihU(gp6367VI4qp}R zC(yijkT1PX^?C4@Ui5U?W;*lC+03b+5oS2+<4EFk&A+jB>_y>` zE4-PUR%lhzJ3?2Agl=*pTc?U~7loZw*JXuFI?nVH3;9EcNqvS%GeTAV4pE=pY7QlH zkj1BpH36iPy$jJR$nntzIHr-K=y?6MKP&@GG|br{_!$S&K)aY<}F!B@XjceYY$`(4X(Z$9)$% z_+6CmzFVAVVtUOPdwzI~KK8ps;ZeQ0Ok*J4tk&ZL)9^ji&j7lZC%PFhKJUU8#9#7QV;a`-mBKQmN23LA)Mw_buo`~gT)wxGT<5sWI z9Q7NmY>I!R6=V=9Kr7G-v_Sy`jhduvjOCfud6nDYX6TLi!VmfPer}HxF+6}7qiU9FPi(Jqi1eQpGf4TvQ!TEL z7T+c<4*q}BNIXBiXpN8tirm2*EDfB}+rZcR3j*K=OW-&Nc`y$8vJeExp_`o=a~>2_ z#LAZ({mlnnl@EYB3tZ~6WpZXLzPI`ghq#W?%sW4p+@dLxLVC5o#Y_o&1U-w*XGgQ| z95wn1HvN%f$HS+!IM3pqmg02jI&x{=VJbao$(iUgp za{D7=Mjlv*ekxc<@hQthwVCy>OHSca%GZxHBGOQl8oHy4U?^zSeR-H)LpzTS7aY1i z8=;0C{aG=%8M~(6oKOD5p1g}!n7^0DVL6B&-Lir>ipzbj3Vmr(uwXH=Fz4$6wDJye z3}Crlu~Y_od0p;P`)&V65Ul^;rEp zx+83!kiPE>VGQqpbjWf1JiZbGI^$7+9By~zyf5aTM>i`J&T~_2-h_(P37>$a0-zJW zs-H(EPW)F50Lkgl72cw=MJBY;7i)`{QJ@Bo- zJQKy+0A$_Gv$4rsCpvdV>d=p zuK*lu{)~h0-b2lq{RA$XQfE6&t5}0t5-oJykJoOexqyT;d<^A#&1ex%rH&SHRBFS` zPG@HCD`GaH2ktcQ-JwjA%^NJW#{SkO z?=o@SXN9g3=Q`)u3xz`#iZcMoR@x#2mmC6@*|bT#<3=B_Kc&Yk2a4L+C0|R)QVt^p ziRiIbiYWQ_kv}TWx9^wLjvvCQRz^68wa~LesUe#G8F8Yh?>4C~mj8gz#i-Mi#Atpy z7xQ^!2@vl$xW_c-ubHc1HnESMRudFP}5}Rcf zLTg|p?pCMzX{856g;?sMtnKV4H!u*+&&s*U;pU&*=+Pfbe~H>?MZfP#z@#L{jyU~d4oT_{QbyLNyWC zywo3?mdTO5EZQ|^dROH59P7O<-=#%9#~Z0U3p!_EW(tyOt329m!DWEs|zYO%yxcv>1pj}i7%Yy zae89wdBoK92%<0iASt?HR-s;{n0`W2dFmEt4G9+^38I;b6&3dq*VQ+p=tO)3b@p=# zj>_ig*ot#NtadXLugu7mVMF4F3>~}{b1YdXAz7HDHKWBf*$ei=_jyQ7MB2Ob$YtQ` z!s6J{*WIjFglfz4u6YVf@M=#s&L_m=1>uVcvsu3M$YXDUTv&)bvnL~C!LX%A{wCLd zqQB0p3H>9b8RLlT$2w=!H>fJj@5PoDAtCY;>a#nO{exHgd1GZVRqgP;)viia8=qfE zwbr?*D!HmEi&9mdk*ac_U1g}Bw&qX{c#9AXr6_+LRzR$>5TKyuZ{fF%&=|1vSqnmK1Bhr|F@tGg`wvOz`(V9wZz(1?_y z{W)Vpei3xW?)Jmotj8ZnI3xUy;6jyNZpjs?;`%JT{R`UQLj;as2DXPwF>49#7m`7B zFp{eT0OwJo^>dL4Z260zOtjt{f1sVWM`4SM|GFZdv!6 zhxaB6r%)ss$s(CA(A|58MdscUa^uV{bSX*QdgMNoT85^+lprwfnOBAX`xlQJQ z6M^91I8bDc+xrF#rTJBM^JRUr&$&}V7@C7#%p@6J6<4NDk*_RE6-fv#6j)&bdQZDm zIX!!GhDF>Yj>OP116Lhxj*?m1f3M>!H}GFdi>u&mVq8(c|d zhC-Fe#6#ShZ~jT-btZ5O7qMK)X@KH@ppj|u82k=cm;Y=Q>s`aXYz$kh{$pokBb1CN zTj=m1C_UewX8z%rV6tcgnim~Cp0xg~BXIX$dRTRU^)xnqav6ujL%6wIZW#9Q8ir^0_d%pN~b#uYwmU#TVd7yzWdE zM(-;HYIB~ua6I(*A2nA53_tv5ohn*bp^88R&l2b{hp#tpeFkpSQ$Xq>e#K@r&n=z; zQKyj%mr~;zYbh4Gz6f^#)e_KSQT*Z(dyJxp$URH z;&TCNbhe@QG{3NK^9QQtyOL-v;a~M--S{T_%e6GIpOQDqGV76obP)qi6X#yY1*Kfl z5ErNRV3?>#KDg%!J@%lQtEQOVSkKV6XZA?neyxyz?#)taugilR`PzYxJdr!gV4wYE zkvog&Np+`gyVXMa<7dkyuCvA4v`Tgi$_4P$9 zdyf+~ZLAar)Ih57yO#08B-UMipDQxEfJs!te5}N5@G_QF^P-(XgSIFO!Z#5h+%`#e z6rlkJBU1(!K$NUO#-zawW|lahI2f5d7>{1|2!3giQ)4M>d0IzjmeSE-;fjo}WS?_t zHJuf%zG^xssYpo+hCjL-tdfY66lry#}{?JI(m|PmeUT~B7gEz_7Y91Y{gxh;6 zl^%~M@%ZB@N%V=Do})fKj#6jwiJG1TD)CgBo|`xSB{MOWwroC_B$SG=w37)gc;-<1 z)1?Pbd^Asd6lqUS=9st2yGr(AY#^V?0i(xGJ18ehD0`!kbWjj;k*Va6(^yy2N%3MO zBZ1~bizzK}FaJ)-*AXp(c<5d>yMN555{TpXbR*K4YS_0VEZ;4mZ|Edkh`w$U2Z|Wz&oP1E2 z9Cd1Zn)E5(9H>4WX!et9zkpJw!tF#O zIib^h%C_2>@kNdj=oF~k4sxHRx6r0!T*O4l`{CipS7H0jk2!aIPG&|0LC2Yf%E)4! zZ{7j(A_zQJwZV2IA>R$9{3qlS@(*P8^_1S4F5TuO$!j|bku$4z1W#e0;H`6 zJ=4!={7gTmN6LQgi=j?u3PX{LD-4w^18fvUKg&kZR9Xs0Q4Uo&YF?J+yc9i9Y^)jn zFF+kzC2}KM%4InJn2SiMRaS|Sh<3sks_mdzuuBpB!aOA*+Gdu?pc@_b%gMYHG0?yh zSwgexF}0BP)+c7V%%Q6VqF$`4boX0fqzWx~b&rmf{l#bzk5ZB)WAH2!JaQjy`QHZk zPiD!q=?JyUo1c=+YDp8kH2bz)nH_m4B(7a=V>UMM{~SQf;SrNIA<+aoZ_6DTD2l^X-(mq?}`?oN1@bBc;er zaoQ=1NEv9SeDb8U(5MyIy7M#b#65Q6ay#);7!CTe!A_KMBj3^V8{W9KzL3s z93=SIC3dc#s86S`vB*EqPFZZHuuaJyVW)i8PMJZ<^>)e(J7pFr0XyYtNl~@+8Q<7A z#)nC@%~tt2N9AdvuDzmNBcjLDV5zYZ%9C20SSZDeqxe|MAH6J(*3thP$Mx@w>v7r(H ziRwzMI>Wpi?IYt=K@A)#z|Z+z#-hBg#|16?#ow04$b`ECXZ}?xFfkY+QXx{K) zT0D@$hUYCZ2T=cV97Yxh4jdGdw~|(^?kQg2Q$Q4?7qZ}cHC8PYV^$rc+x%(bzr%cG z8Hxktv_`tc#2wk<*t{8O!|CRK2x(D5j?jRXjJMyWFxd(tC??x9EMC~~GnJ>@s@ke# z4m4QM!H&xUHTcs9qDm3x8;s3E!-GbwR@!9j@ETi^h2N@SP`Y`EVs0FX09jCi)ekNm zE0wX1{Qe2y&5BfvSeyvjeor|^H>!*E$}Q&EOT;}Hur`3T0jy(prmWt*wOLCQgJl-+B-BamOawDYC1Q+K;Tl|*xs$rHc^5iAieIu zY5l`HD>4V-BYnJZMxpcXb;gz?aUXGOrhD&?*4Y%zBlw}8WdFD-j6ysEd>naiWH|fmvDRtkF9oBw;peiRo02Bmy%??p zq@I*OLH0bdC;2kp8reTGbhWY34Djvh2~=$yG{;MU!;EfI<{C~e%&zv5VKBE|6;}F}wWj=XVOYNxpSOdMrCaeEySxJxuZuE-CwV~la)~F21E!mmd#$!nf z3CfdsZX0(}K}nN$>AqS%k`#wGw_W{j%WXFrM`bW!VtJz3l9Aic(0N9#_@u$ZQ0Ih( z&Z1m;thy))K#~0uXtdFYCqXaVJzkt##ztRmJhCrKp5=v$sIR2RZML`F%x%RQ)Ug4d zT)x}}Uv4ATq7>@QP3=+Dc{JxnN|?tMwY|YS1Ax)jh66?7A8-GJ%EP&B3bG20z)1Sp z3K1XaC7$1Dusr>I+DlulGrX%aY5~eX?`jV{VI#j<2FPesXRSb3!4_}Y?xxUCAQ}R! zNKmM47P$v=eVr8oN~~9h9nQD(N=>z z8Rq94$>FxuD&}1l+%xZTYfk5(0GSVCongMEa(tnZ2Fv>%pQ3T~<|9RzD&yi+l*L6{ zL!@~JW1Z6S{3b4wH=te7Dd0VS9&mBK+9iu6l+gc?xJ&+6foyf{NanoKI5JJ-)<*U1 zDUkwaFUpS^6!(Tw9Vh}Kb02Icso{le2t1J`_h*F%8UEK&ZiS!2t#H);n$Pgxu8zTN zIRt_Sw4(g?;BZ)gkDS8C2n5^(X3yEz+7IB^#+t)YpeehEzbcpnB#ng1@BM*k0BTKT>L zlNT_Jx9b8<+yI|#3T$aGX*b2So3`4((r((#jUfAaHUx)wrC{cwz&^GK#hNSQ&6zm*jeE7Jadc=N6CXl3 z%6E|UoM@K+Az*yRrN?HX7WM_+udG59CS8S8&w9SXcI1<6rGWe2#SNK;G7SqqM!C$m zOTw<&372V)$F0j0FV2LjAmRQS7T->ec}NW=XND$Qcmj#9aMd2E2puLE$Q8Q#i_nA> zlar+=+*(@7qebn6iqHj-82HqabrWD9*-|~cxxwI z67J_sUY%_bEMEC2npC?u2d@jC;eR0zyOHC=ZRW*6xC(Naw*$bxsrrsiXIt~AaG1A_Vq zT3V)ADXnSp+RoSf6bVV~VI2nj@@q!xJ2t1unPvCTWRzUpH zJxw~r;5H5aZ0yS~puT(0=;I~>b}L6Y;H0Ur@(pHXSDUv4XX{yhIJRtWc}vJA|1Ot* zWnK=iW>CX_P=jtfq5~Q^g}fpvOOsZ=g@qvTGyaj~3TXt4wDVlKVQZjr^E{Ae`6w&( z(PQ$_&HU@NInYZwFjs+0RjA3ze<;*6q3P^18Ufo39I1?13wJ_Et$~t_;*AgA9;vyG z=yllcKuJ5r=#IDW*ElThFKP6}O8fa8o#qc23-cMkdq}&mHG1pAv89Y!ZKU(KEb@AT zRb0{#z4b8$w#sNCX?xdOUdPVp^p)PFpO1lA)s~5q+RAuKeHAQM27FGmehhcf7b^H) zzgw#lN3@LQM8jAA@Wioo>aDFQ;diw7Fthm=164sBj9-_E%W}Wb6q`s``*%jd4?2ym zfU(zG{s{}uj(5D}d$m_7#fLR<*XyC|WSpbYczO3k9E?P|YqSSsZlZPWbMM7>ZL`mD z$nQ9aHcQRIyS%YQXqbO9>2vQ4>0TVAl*eOw(%o2-1K(Z$u;qZJU_#i>xFPm1g>Ltj zyl!mWalluy31->5V;}79#OMu=JnT(wlp>tQ^p(~slnB`4oEEtw_Hc&Ru?>C1@F!Bz zVP7=7(r>)yi@qv*@Rs^J_z$cy5+i|0Pj9#U|G2k;i-}A4?~QzZx$Ud|>u^Mzj(izM z#O(3}9MN8FN{>2FF7I|9_i8_F_C_`(8EYA6?Z*$;D6sZ&;4Q=8Eyt}wOfb?oUb(&D zBPaIcuaXB+)@1&?*cj)N z$B7C7vnn?G1bBGe@cAbI zWC1>~4zIoJ-vP#dv08i?7>N&I7gIe6z4&kSV&tS)cK?%laBr#yYi+HC%c#q|`)xTm zK8Nm_pY1*lgcOir2CG(Wf$c!jy!>4n-nEYt#aLlh@zG?1>3|TS1IK@l=%PX3GrX(L zr3fY;dsJ<*xB|f=m(h)Ly=AB2H(z`4@5@f-D*6}06>wwO18GGHE28x>z~=9#$bjZQ zKJsW%Z+JILd#P@90UznH|IBz%E((JX>gW#CLkBN2U-y9(#v}5r-@S9;&4watFaR!p zRGIxil5)(R#YySjFx!(D?h zh|%qLuM3|R`TeW%Ar!@v8LgK}ys_*eNTV@$nHN;no_iC=r$(L1#httj8gE4(RtbPs zJ_)dvi_ii&D$TYY_ampQmU^^03BT+GHSM|{IjJtAPNh&CYaz%QeNa88iWOhzK4TY5 z`rlwQ$JqsXC{VU2ib<(pOnmN5TKxf1dkO2;;;uBoyvN&%yAGX%D|hwaZqv>l+@&55 z1Y+N?qsj7Msn4bdu%{k;r?JG!rc{VZEW6ebFGuhz4)^fOXw)rxnkgqwofPmsF54*fStT>^P% zA5u5HFR446_*BqRNL>afuO?_0DSb#?F!u0CbdHoBBDXdCc0zm{``umI1G~5}Zhg3i z!X5I#XNqUCD^ujH`e7V-_tLhhv@A{A-tmJULqUoZZF}+!!H@7tA#69K2-_@)_i}R| z!uG$mO$PK_p&m7bJ(Pn&{f;i-Ei8@2RcIKu@R2YZHuY)(6pCg=?p(>uoA+&oS5cYjTARp#%+nw4r7+W=FmF4jXkK zlejT(M$d$0)B5$#Es`)a1BC zZhGm;zlDJ3*vr=+g`A|9uU;ff?7{3pkT3BDHxb3Jvf)&#m%_hT^~0df8etI3AsqOz zgbC^8fNiDu#W2dm5DibjTK!5e#p_5m_v19|woF9^vDA{etQOlk#j~8S-r7k$OYY|I zE}1a5q*eos@sUyO)w5FC}$Tb{IB*=Ro9mbn~v-Tvi( zenxarc71ZuprybwdH=%x$Xh}g;VcKjw0hZw3tc>dZmF(K?A9H}ajeN1tyXtPy0{jV zAShb(N<5otb?>CRxSbv9BMv82lHPtJT zU5O)CC!+5VTht`V^2%UZQa|^DtarN_GeFSr03~<#{v~c*K?)}m z;WJ~)GVs};e3~u@C{H@xzjRtf^13q_zGCUoWU?S*;l)aq()$;DOzc|G*l?g<>4d!6 zNz1cO4~Sjd2i^hg-sPuZ<3_lI#C7M3C`1g?64!E@@*m|9N$Wg0z^B)oLyHi560foC z&t5oGxFXDOh;~MO2sS3ur`;jPoapIDI>jneBrvGE-7PMk`?|j{uEf)+u`ghlcq_LL zO|`oBKr3oeTgK052+rq&AXWhvt$NfUEs!Tapr;mA>aThCr}+Mr44Wrvl>hc zJGXG2L>NuSDv5VMcwUaGvsPvNgZtc8LgPkrb;nUj6Llo5egu>L++o*aD>Hu zvhL{SKlU9@ONFWWlm!8tCbGl38O+GKo(pF<6x<3`{l8ZC!!RP=}!N`;z_ch&dG3lLGhbBq+m2ze#_D zx4&fJW8V%3Qn58*=>bkXuy*rtZ>orB|NvrRBvd?=C7w z$M8JWjDFmWK*z^ru3;7(TsnL3Ypib!eH69%r~|)F6oEDjy)BCzIgWPMP=YeHWC(e) zCf09QbdfuMcsJ7bbM@JH9V;wQ4Yd90nfTSqLv<>qKmN9blf_H@Q+K!fvetl<_xv!{wrciZn+UIe&ArgpOe zO&wVK?fh=G)6pwhCc82+1`KGPoJaiEOOypLfobM{f_5BdPLtaxE4)fKJ^@eucE12t zDVU%Nt=u|_!2>{0aAXKW*Q6SoRua%-e^CvR13=b;t)fhh{n@{!3C2-@`*`?6QPY^w zTXc`QKyOiUwp^rCSSpN@*o+@9j;M z$=K8!^UnZkrLos=M&)b@L@ah6Tzom2755%O06ccw-cXixj)}=sG7!z)%R~q}V~g^v z!G?1NA4KAwsB@}(2{tvXhAd-4NQua>SLm~Gu zKg09`S{td&q1;A_#lkLy1~OJa+9Noi9FL{vLZSKLMwQp>*Ymk`Ej_r@o$rz!T)>hkb4IfQ_=Rt;`y3KA9@&Wv;1~_%^UUN;}jHNgb1MNf~o2eSaE~ zDTqMcTa;hP8CP9t0VymK%1Kf}$jwlp;f3a%s#Ik^@nP%nWa1eJl^jgHTa6fIpB_1y zr7e4eG@VeJx|AAyw$!7pe=n_4*H=m_xCV(_QzqBg50ll}bH{^@BVytdEG;I$gEq1b zlo4f<01mLq*9W>#hnj&SOx(IZfNMGYdVjGXJS8^fqJV+n(eZ%0YvBdj$P85bqkC?9 zP)lO!U@)32oC=m;O{7iT8*q>_xnLKEnK)nyAUrA!l<)0RpR!`iJDpW}`2Y+C zGXr9JeE^?L)VJ_q*_RjVIH*v~)RzC4r4T1gw&$AInDV~O zc{5;aQO$|t@{(X37vmxd30=_rVW_mHzwC&?r#8KOhxX!t`=&BWneI^oJtz26>lf59-q+^Mt}M+)@oY&n~Po4V|t~ zSpKz`Eh99f|K*v<9me+@R?ygl?}D#tukOZH4ndTk z%m))!%c!|Ot0`LqJ-#Ux3GQxO+@^ zH-W$C>M7(|Tpo0PP*Vu2v>Ar(S%oz4fC`@ggckV?yQZLFB^+Eys40Z>f?rV^ztUML zM2pm@tY0KL*xiZCbD2~+QA*S#gU3;m4nqr>gdnJzY`XEFn%KfKKR;dZ%rf(BD=Ohf zBJa_-gO(CdyhVxESC}hA$HlXTt_*4+t2Ce(LgyGc5l&2f@KFd zlOqfrN|D_I7uFbcKfdLt6K})K$<8@i&8|#qmRz!|nR0Ph-;hhTHAOB?%O{t9)_A$( zSeMJiWnCHn*6DJ|xANpN&~nN}!x5o(wZ;tW4TPuFRl-MW zue4RO-RS3!%{*icM$%z4Dg~TC`9_e0=gED(q~}}1+X^qm)2-qZqa^-USO+`^q=q(_LG5FDDm2>F5K!qnXy7wB=})b(>rqs+&i% zt!eV)v;uPJXHAq#j^&n%%Niq>{?=%@46x3XORhCiE_qgwT=K0!av4aBKQ5}91U9uc z3N1&~s7mNudOgGO+#K!u{AQ(o^WuFlBs`RFJef=gX3gs|8F~Prcr_fgk|uCzVy*ir zakPKI?+JcS@%uBs7x=xxuZiDAe(n4^`0eHQF24`>eai3JZfC}={O;y=AHNm+e$MZA z{Qk^u4Zmi7+xhL`cYxnvepyGH83Xw}$nR(Te#!5@_&v?%4XJ+vYCa?7;I)W3gel0s z!T{q!?8`df)6fC;paZU>1I`hF^W8QfkD>$a(r1TfDfN=+sCb*~i0Tjjh>a18{RZ>B z5eUDVaig<1%Q%S0YY`$fQ44qYjCrVq*V2D9)T)hjM5Q@}Uii4U=!GjU7!pn%MhNv{ zG^$YwZ{S#!fG8Z;@j_qIqXIr&j_nr`;Y&w5ymcYgics!-2jLja-`xPT%J=CpVf0b! zI;SN^X@;L64l4aMvV^dyjQ1*sw=f0a>yujDM#z?rEd_ztrL{_P)h6cXf&Bb6r94vi z2QrDg#UrZja#O{k(;_#7jv_9Qai?e!l+g_qnLF6)n!^`RshGuUb#wW6jkMiYe<1V? z!#__FCB%yRp!U#|uP+&~2!2`6uJg~eMI`IO>@%d;dJ_mIM4v-U(+L$9!#K^|npUW9 z75sB=TzJ`6DbwF`y@0G!l<5H(f_WjUJqq=M<_pX^PJkH-_2B9JuYm*G6xCYUP?ghwZew){VMj=k)tAh`Bl#+*4=D1XSfR=f0wQ1G+;wh{&PP~ z!NeNcsKOfLrM8-_Y&D@Uj46i;)A*rLCMTyT-Of-GP+1Dg!0YB0hzGDexwNMu^W`;c zbJaey3U*WJ#HL*eh&tcgXHp8pdW*k{k8v7=wx!_=ZAvku{xgX(8I1a03eG+RwGA5I zyFVEH-g9WA>Cx)<#C5MUHtK&00n+`)k0hlB(dv(av2jR`>KdoLGce;C!`EF#mYsff zw~o$W^v;Kpg)e(RME`FqlisQ&1fXGmWzIs#8!)N~K;zBxMg32L3nImG1;^g`k{0NzTRS58#gU|UX}9rNL~TrWg;Zx^T=marxpSSK(+c;C>VLd(kDYp;pb9_*;w?G^Mi90#C+$ zMkiK5O8SerHaVuZP<+H(oM8A6Luz#kXp7;06j$uCTXo0B3GwYkK%Q&0wa*r*Uc{;i z5a@p>Sl*1oeIg`i4|S4-`W|J~-Db4lQX*9q>u4Mb_go6osvo7gZK}Hbp6YU_F5vjg zZ@de7Jf|F(3J9mBx;1G<@W}YX4cVcyC#~=uxoWvThu|Q7SM9!Ila}+w7I0H+jupVG zQ9t}L6k+v0XX4m#-X)g=V+%5a?(joeWHBvdubs*+ws7?MeS8(DE=PEa8J9Io7EIzp z8e7!+&FS~ErGKI&2{$7DDq0|XP6itQYpQd8BrzGRe^64)*u6N;V(Kj~yfVS)-5}~D@0b$RoeD3E6 zVeTy|=0WugH^Zu+NUET}kuS33flO`LU${%+sbEsJaecO~K=2!q7>vEB-#?l7T(+V0 z+kb>ai`jy_wf%TeAfdE5SDg=e>XmZR=;E=Ec*v zj+4jM71@_A_YLA>kdTkTjm4e5%t_hSs1^MtNwMk76KjLrSC`$KOK#Os7Rlx$P zyfB;^26L}T!{Ed9{~HW$`NzKl11+*lFeeR%OSG5zVPKwxz1VO4vv{L$1c#H2e*7}qI5KXx4WDYq!D^#BAoh}JG`Yh@ z6GyeXnMFp6Y*ipaaXR2WUNc&I30X!9AUZN2oVUgX54+ts;9*fG%24dV(r!5nbvMk% z-Hfo`iW!sJ3Kk<#z%FkPA~T(jC3glwc^z{|k+}MdR^_M|rMq+F%*TX(35YxFP-Pm_ z533KvBRQ)a!IX(P0HN@eHzx~kyg~uG$iWc@xVMG1p}d7@NW&9jSi_Tr)#OM`#s^CU zG=hm0lWcGc5Wz&S@GfYN9dKG)u3<03>W@%=QBg2Dt2nB=yy=k3?4un z@$hhOv$rbK8~N6l4DRH#&r4Vvxc}GqCz_c*=IS2*DpRxuf59z5BN=G;h*?|s$6fZB z0CYz{QE`otee^I#Oqro?8r#fi?{PXA*~$@+b14~l$%v6l

u_us0&TNlnd@sxl+9 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%0DtSJ(})2nc+t>*>0iU*<+O0Mpno1 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 H%&i33| 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

&*b-$&PDUyd@U&Gt_CJNOi;qgS#$ zfetF8yLm?Fqi>>xiZzGv;j`)=A;*Y~V_`u3yOuOFyUKV*F;6%cMewtno^jh)m)xPJfo zk*hzmYfV40|L7-gJ+!{@k(a)k40X-9vDkQ-WBi|PDsr7=0upO%O{}RkvldpSo9*h| zLbup0b?e}s7_p&{`m+uvNrCzyL?bUjXUbENkb$U*3 z*h_lj-n2LCEqcpdx}WLm{anA$FZRp*O25{x_nZAzztcDR!~Up0?oax&{=C2JYlF-n zJID?4gW{kxs0^xu`k*mr4cY@^;0#8CWH1>_2lK&Vz&{jG+mG*T+M1JbbSLi=ow8GP z>Q2*XJBBlK5@+JfoJFtvFyZZwUyVHiUrF($^$SQwg_F?BO<7R|C*HS1>6Y@3ETG!t`T&di0W zSs6>W@>bC*TUD!WHLbQ~SVJqp(=+_6bu;)mkDtrkYFFl>c9B6jh&e&O7 zw{v#hF4#r8WS8x#U9;j#?LEwJMffSra+6A}VS~u=QDPu&fHl#X*cWU+=5$jD{jqg zxGlHiI_}6FyHj`WF5R@3^>W00$*U0e4Pw4S%#XaWH}&S;(o6eUKj#zrMME;;zrzxJFydw z;&D8U=kYSu7F)Fdx1^1%kuwTL$*34LqhYj+j^P+1V{A-~xv@0TX4cG^1+!#U%$nIS zTV}^}%#k@Zr{>&TnrSO*<*b5LvMN^1YFI6+V>#A{EI9qAJ?->HD(lTv&f_38?yZQO zf7J@Dcbh5`4^1Ya9!nJLuKEI%Dt;qoL70bst-5u$>9$?N z9lD7-acAzr)x3*LkAy85-%b#A1tbTlU1^MWRkJ}1g^M0kVD-y!!; n$@|)bdwTvZ*T1T|0{%6V{%vl^GT(L9eZq>*lF8WZ-}d@51G9(y literal 0 HcmV?d00001 diff --git a/LightlessSync/lib/OtterTex.dll b/LightlessSync/lib/OtterTex.dll new file mode 100644 index 0000000000000000000000000000000000000000..c137aee184d789102648a05ecc24c0437df54ba1 GIT binary patch literal 42496 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 F{{cAyTipNv literal 0 HcmV?d00001 diff --git a/LightlessSync/packages.lock.json b/LightlessSync/packages.lock.json index a7576db..e1b339e 100644 --- a/LightlessSync/packages.lock.json +++ b/LightlessSync/packages.lock.json @@ -105,12 +105,6 @@ "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" } }, - "Penumbra.String": { - "type": "Direct", - "requested": "[1.0.5, )", - "resolved": "1.0.5", - "contentHash": "+9YRQxwkzW6Ys/hx8vHvTwYV76QMjbf7Puq5SibxVLNzkPLyKLp7qZCKS1SC4yXPJlPB4g80IqxrxCm0yacMFw==" - }, "SixLabors.ImageSharp": { "type": "Direct", "requested": "[3.1.11, )", @@ -139,6 +133,24 @@ "resolved": "16.3.0", "contentHash": "SgMOdxbz8X65z8hraIs6hOEdnkH6hESTAIUa7viEngHOYaH+6q5XJmwr1+yb9vJpNQ19hCQY69xbFsLtXpobQA==" }, + "FlatSharp.Compiler": { + "type": "Transitive", + "resolved": "7.9.0", + "contentHash": "MU6808xvdbWJ3Ev+5PKalqQuzvVbn1DzzQH8txRDHGFUNDvHjd+ejqpvnYc9BSJ8Qp8VjkkpJD8OzRYilbPp3A==" + }, + "FlatSharp.Runtime": { + "type": "Transitive", + "resolved": "7.9.0", + "contentHash": "Bm8+WqzEsWNpxqrD5x4x+zQ8dyINlToCreM5FI2oNSfUVc9U9ZB+qztX/jd8rlJb3r0vBSlPwVLpw0xBtPa3Vw==", + "dependencies": { + "System.Memory": "4.5.5" + } + }, + "JetBrains.Annotations": { + "type": "Transitive", + "resolved": "2024.3.0", + "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug==" + }, "K4os.Compression.LZ4": { "type": "Transitive", "resolved": "1.3.8", @@ -508,6 +520,11 @@ "resolved": "9.0.3", "contentHash": "0nDJBZ06DVdTG2vvCZ4XjazLVaFawdT0pnji23ISX8I8fEOlRJyzH2I0kWiAbCtFwry2Zir4qE4l/GStLATfFw==" }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.5", + "contentHash": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==" + }, "System.Net.ServerSentEvents": { "type": "Transitive", "resolved": "9.0.3", @@ -524,8 +541,28 @@ "MessagePack.Annotations": "[3.1.3, )" } }, + "ottergui": { + "type": "Project", + "dependencies": { + "JetBrains.Annotations": "[2024.3.0, )", + "Microsoft.Extensions.DependencyInjection": "[9.0.2, )" + } + }, "penumbra.api": { "type": "Project" + }, + "penumbra.gamedata": { + "type": "Project", + "dependencies": { + "FlatSharp.Compiler": "[7.9.0, )", + "FlatSharp.Runtime": "[7.9.0, )", + "OtterGui": "[1.0.0, )", + "Penumbra.Api": "[5.12.0, )", + "Penumbra.String": "[1.0.6, )" + } + }, + "penumbra.string": { + "type": "Project" } } } diff --git a/PenumbraAPI b/PenumbraAPI deleted file mode 160000 index a2f8923..0000000 --- a/PenumbraAPI +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a2f89235464ea6cc25bb933325e8724b73312aa6