From bfa41fdd966ff8a2c1cb4708378c8ea026995728 Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Mon, 17 Feb 2025 13:01:13 +0100 Subject: [PATCH] update settings ui character management --- .../Models/Authentication.cs | 1 + MareSynchronos/Services/DalamudUtilService.cs | 12 ++ .../ServerConfigurationManager.cs | 18 ++ MareSynchronos/UI/SettingsUi.cs | 170 +++++++++++------- .../WebAPI/SignalR/ApiController.cs | 6 +- 5 files changed, 142 insertions(+), 65 deletions(-) diff --git a/MareSynchronos/MareConfiguration/Models/Authentication.cs b/MareSynchronos/MareConfiguration/Models/Authentication.cs index 95e6bdf..f081bc9 100644 --- a/MareSynchronos/MareConfiguration/Models/Authentication.cs +++ b/MareSynchronos/MareConfiguration/Models/Authentication.cs @@ -8,4 +8,5 @@ public record Authentication public int SecretKeyIdx { get; set; } = -1; public string? UID { get; set; } public bool AutoLogin { get; set; } = true; + public ulong? LastSeenCID { get; set; } = null; } \ No newline at end of file diff --git a/MareSynchronos/Services/DalamudUtilService.cs b/MareSynchronos/Services/DalamudUtilService.cs index 8825f4c..336a02d 100644 --- a/MareSynchronos/Services/DalamudUtilService.cs +++ b/MareSynchronos/Services/DalamudUtilService.cs @@ -270,6 +270,18 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return await RunOnFrameworkThread(GetPlayerName).ConfigureAwait(false); } + public async Task GetCIDAsync() + { + return await RunOnFrameworkThread(GetCID).ConfigureAwait(false); + } + + public unsafe ulong GetCID() + { + EnsureIsOnFramework(); + var playerChar = GetPlayerCharacter(); + return ((BattleChara*)playerChar.Address)->Character.ContentId; + } + public async Task GetPlayerNameHashedAsync() { return await RunOnFrameworkThread(() => GetHashedAccIdFromPlayerPointer(GetPlayerPointer())).ConfigureAwait(false); diff --git a/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs b/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs index 42a5013..a6b367b 100644 --- a/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/MareSynchronos/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -100,6 +100,7 @@ public class ServerConfigurationManager var charaName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(); var worldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(); + var cid = _dalamudUtil.GetCIDAsync().GetAwaiter().GetResult(); var auth = currentServer.Authentications.FindAll(f => string.Equals(f.CharacterName, charaName) && f.WorldId == worldId); if (auth.Count >= 2) @@ -115,6 +116,13 @@ public class ServerConfigurationManager return null; } + if (auth.Single().LastSeenCID != cid) + { + auth.Single().LastSeenCID = cid; + _logger.LogTrace("GetOAuth2 accessed, updating CID for {chara} on {world} to {cid}", charaName, worldId, cid); + Save(); + } + if (!string.IsNullOrEmpty(auth.Single().UID) && !string.IsNullOrEmpty(currentServer.OAuthToken)) { _logger.LogTrace("GetOAuth2 accessed, returning {key} ({keyValue}) for {chara} on {world}", auth.Single().UID, string.Join("", currentServer.OAuthToken.Take(10)), charaName, worldId); @@ -139,12 +147,14 @@ public class ServerConfigurationManager var charaName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(); var worldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(); + var cid = _dalamudUtil.GetCIDAsync().GetAwaiter().GetResult(); if (!currentServer.Authentications.Any() && currentServer.SecretKeys.Any()) { currentServer.Authentications.Add(new Authentication() { CharacterName = charaName, WorldId = worldId, + LastSeenCID = cid, SecretKeyIdx = currentServer.SecretKeys.Last().Key, }); @@ -165,6 +175,13 @@ public class ServerConfigurationManager return null; } + if (auth.Single().LastSeenCID != cid) + { + auth.Single().LastSeenCID = cid; + _logger.LogTrace("GetSecretKey accessed, updating CID for {chara} on {world} to {cid}", charaName, worldId, cid); + Save(); + } + if (currentServer.SecretKeys.TryGetValue(auth.Single().SecretKeyIdx, out var secretKey)) { _logger.LogTrace("GetSecretKey accessed, returning {key} ({keyValue}) for {chara} on {world}", secretKey.FriendlyName, string.Join("", secretKey.Key.Take(10)), charaName, worldId); @@ -250,6 +267,7 @@ public class ServerConfigurationManager CharacterName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(), WorldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(), SecretKeyIdx = !server.UseOAuth2 ? server.SecretKeys.Last().Key : -1, + LastSeenCID = _dalamudUtil.GetCIDAsync().GetAwaiter().GetResult() }); Save(); } diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index 6c03267..d8f5c2c 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -1,5 +1,6 @@ using Dalamud.Interface; using Dalamud.Interface.Colors; +using Dalamud.Interface.Components; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Utility; @@ -29,6 +30,7 @@ using System.Globalization; using System.Net.Http.Headers; using System.Net.Http.Json; using System.Numerics; +using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.Json; @@ -65,6 +67,7 @@ public class SettingsUi : WindowMediatorSubscriberBase private CancellationTokenSource? _validationCts; private Task>? _validationTask; private bool _wasOpen = false; + public SettingsUi(ILogger logger, UiSharedService uiShared, MareConfigService configService, PairManager pairManager, @@ -1405,6 +1408,7 @@ public class SettingsUi : WindowMediatorSubscriberBase " Make sure to enter the character names correctly or use the 'Add current character' button at the bottom.", ImGuiColors.DalamudYellow); int i = 0; _uiShared.DrawUpdateOAuthUIDsButton(selectedServer); + if (selectedServer.UseOAuth2 && !string.IsNullOrEmpty(selectedServer.OAuthToken)) { bool hasSetSecretKeysButNoUid = selectedServer.Authentications.Exists(u => u.SecretKeyIdx != -1 && string.IsNullOrEmpty(u.UID)); @@ -1452,6 +1456,35 @@ public class SettingsUi : WindowMediatorSubscriberBase } } ImGui.Separator(); + string youName = _dalamudUtilService.GetPlayerName(); + uint youWorld = _dalamudUtilService.GetWorldId(); + ulong youCid = _dalamudUtilService.GetCID(); + if (!selectedServer.Authentications.Exists(a => string.Equals(a.CharacterName, youName, StringComparison.Ordinal) && a.WorldId == youWorld)) + { + _uiShared.BigText("Your Character is not Configured", ImGuiColors.DalamudRed); + UiSharedService.ColorTextWrapped("You have currently no character configured that corresponds to your current name and world.", ImGuiColors.DalamudRed); + var authWithCid = selectedServer.Authentications.Find(f => f.LastSeenCID == youCid); + if (authWithCid != null) + { + ImGuiHelpers.ScaledDummy(5); + UiSharedService.ColorText("A potential rename/world change from this character was detected:", ImGuiColors.DalamudYellow); + using (ImRaii.PushIndent(10f)) + UiSharedService.ColorText("Entry: " + authWithCid.CharacterName + " - " + _dalamudUtilService.WorldData.Value[(ushort)authWithCid.WorldId], ImGuiColors.ParsedGreen); + UiSharedService.ColorText("Press the button below to adjust that entry to your current character:", ImGuiColors.DalamudYellow); + using (ImRaii.PushIndent(10f)) + UiSharedService.ColorText("Current: " + youName + " - " + _dalamudUtilService.WorldData.Value[(ushort)youWorld], ImGuiColors.ParsedGreen); + ImGuiHelpers.ScaledDummy(5); + if (_uiShared.IconTextButton(FontAwesomeIcon.ArrowRight, "Update Entry to Current Character")) + { + authWithCid.CharacterName = youName; + authWithCid.WorldId = youWorld; + _serverConfigurationManager.Save(); + } + } + ImGuiHelpers.ScaledDummy(5); + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(5); + } foreach (var item in selectedServer.Authentications.ToList()) { using var charaId = ImRaii.PushId("selectedChara" + i); @@ -1463,8 +1496,6 @@ public class SettingsUi : WindowMediatorSubscriberBase worldPreview = data.First().Value; } - var friendlyName = string.Empty; - string friendlyNameTranslation = string.Empty; Dictionary keys = []; if (!useOauth) @@ -1475,19 +1506,11 @@ public class SettingsUi : WindowMediatorSubscriberBase { secretKey = new(); } - - friendlyName = secretKey.FriendlyName; - friendlyNameTranslation = "Secret Key"; - } - else - { - friendlyName = item.UID ?? "-"; - friendlyNameTranslation = "UID"; } bool thisIsYou = false; - if (string.Equals(_dalamudUtilService.GetPlayerName(), item.CharacterName, StringComparison.OrdinalIgnoreCase) - && _dalamudUtilService.GetWorldId() == worldIdx) + if (string.Equals(youName, item.CharacterName, StringComparison.OrdinalIgnoreCase) + && youWorld == worldIdx) { thisIsYou = true; } @@ -1500,61 +1523,84 @@ public class SettingsUi : WindowMediatorSubscriberBase { misManaged = true; } - if (ImGui.TreeNode($"chara", (misManaged ? "[!! MISMANAGED !!] " : "") + (thisIsYou ? "[CURRENT] " : "") + $"Character: {item.CharacterName}, World: {worldPreview}, {friendlyNameTranslation}: {friendlyName}")) + Vector4 color = ImGuiColors.ParsedGreen; + string text = thisIsYou ? "Your Current Character" : string.Empty; + if (misManaged) { - var charaName = item.CharacterName; - if (ImGui.InputText("Character Name", ref charaName, 64)) - { - item.CharacterName = charaName; - _serverConfigurationManager.Save(); - } - - _uiShared.DrawCombo("World##" + item.CharacterName + i, data, (w) => w.Value, - (w) => - { - if (item.WorldId != w.Key) - { - item.WorldId = w.Key; - _serverConfigurationManager.Save(); - } - }, EqualityComparer>.Default.Equals(data.FirstOrDefault(f => f.Key == worldIdx), default) ? data.First() : data.First(f => f.Key == worldIdx)); - - if (!useOauth) - { - _uiShared.DrawCombo("Secret Key###" + item.CharacterName + i, keys, (w) => w.Value.FriendlyName, - (w) => - { - if (w.Key != item.SecretKeyIdx) - { - item.SecretKeyIdx = w.Key; - _serverConfigurationManager.Save(); - } - }, EqualityComparer>.Default.Equals(keys.FirstOrDefault(f => f.Key == item.SecretKeyIdx), default) ? keys.First() : keys.First(f => f.Key == item.SecretKeyIdx)); - } - else - { - _uiShared.DrawUIDComboForAuthentication(i, item, selectedServer.ServerUri, _logger); - } - bool isAutoLogin = item.AutoLogin; - if (ImGui.Checkbox("Automatically login to Mare", ref isAutoLogin)) - { - item.AutoLogin = isAutoLogin; - _serverConfigurationManager.Save(); - } - _uiShared.DrawHelpText("When enabled and logging into this character in XIV, Mare will automatically connect to the current service."); - if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete Character") && UiSharedService.CtrlPressed()) - _serverConfigurationManager.RemoveCharacterFromServer(idx, item); - UiSharedService.AttachToolTip("Hold CTRL to delete this entry."); - - ImGui.TreePop(); + text += " [MISMANAGED (" + (selectedServer.UseOAuth2 ? "No UID Set" : "No Secret Key Set") + ")]"; + color = ImGuiColors.DalamudRed; + } + if (selectedServer.Authentications.Where(e => e != item).Any(e => string.Equals(e.CharacterName, item.CharacterName, StringComparison.Ordinal) + && e.WorldId == item.WorldId)) + { + text += " [DUPLICATE]"; + color = ImGuiColors.DalamudRed; } + if (!string.IsNullOrEmpty(text)) + { + text = text.Trim(); + _uiShared.BigText(text, color); + } + + var charaName = item.CharacterName; + if (ImGui.InputText("Character Name", ref charaName, 64)) + { + item.CharacterName = charaName; + _serverConfigurationManager.Save(); + } + + _uiShared.DrawCombo("World##" + item.CharacterName + i, data, (w) => w.Value, + (w) => + { + if (item.WorldId != w.Key) + { + item.WorldId = w.Key; + _serverConfigurationManager.Save(); + } + }, EqualityComparer>.Default.Equals(data.FirstOrDefault(f => f.Key == worldIdx), default) ? data.First() : data.First(f => f.Key == worldIdx)); + + if (!useOauth) + { + _uiShared.DrawCombo("Secret Key###" + item.CharacterName + i, keys, (w) => w.Value.FriendlyName, + (w) => + { + if (w.Key != item.SecretKeyIdx) + { + item.SecretKeyIdx = w.Key; + _serverConfigurationManager.Save(); + } + }, EqualityComparer>.Default.Equals(keys.FirstOrDefault(f => f.Key == item.SecretKeyIdx), default) ? keys.First() : keys.First(f => f.Key == item.SecretKeyIdx)); + } + else + { + _uiShared.DrawUIDComboForAuthentication(i, item, selectedServer.ServerUri, _logger); + } + bool isAutoLogin = item.AutoLogin; + if (ImGui.Checkbox("Automatically login to Mare", ref isAutoLogin)) + { + item.AutoLogin = isAutoLogin; + _serverConfigurationManager.Save(); + } + _uiShared.DrawHelpText("When enabled and logging into this character in XIV, Mare will automatically connect to the current service."); + if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Delete Character") && UiSharedService.CtrlPressed()) + _serverConfigurationManager.RemoveCharacterFromServer(idx, item); + UiSharedService.AttachToolTip("Hold CTRL to delete this entry."); + i++; + if (item != selectedServer.Authentications.ToList()[^1]) + { + ImGuiHelpers.ScaledDummy(5); + ImGui.Separator(); + ImGuiHelpers.ScaledDummy(5); + } } - ImGui.Separator(); - if (!selectedServer.Authentications.Exists(c => string.Equals(c.CharacterName, _uiShared.PlayerName, StringComparison.Ordinal) - && c.WorldId == _uiShared.WorldId)) + if (selectedServer.Authentications.Any()) + ImGui.Separator(); + + if (!selectedServer.Authentications.Exists(c => string.Equals(c.CharacterName, youName, StringComparison.Ordinal) + && c.WorldId == youWorld)) { if (_uiShared.IconTextButton(FontAwesomeIcon.User, "Add current character")) { @@ -1624,7 +1670,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.EndTabItem(); } - if (ImGui.BeginTabItem("Service Settings")) + if (ImGui.BeginTabItem("Service Configuration")) { var serverName = selectedServer.ServerName; var serverUri = selectedServer.ServerUri; diff --git a/MareSynchronos/WebAPI/SignalR/ApiController.cs b/MareSynchronos/WebAPI/SignalR/ApiController.cs index 62b7237..7580f95 100644 --- a/MareSynchronos/WebAPI/SignalR/ApiController.cs +++ b/MareSynchronos/WebAPI/SignalR/ApiController.cs @@ -261,9 +261,9 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM Logger.LogError("Detected modified game files on connection"); if (!_mareConfigService.Current.DebugStopWhining) Mediator.Publish(new NotificationMessage("Modified Game Files detected", - "Dalamud has reported modified game files in your FFXIV installation. " + - "You will be able to connect, but the synchronization functionality might be (partially) broken. " + - "Exit the game and repair it through XIVLauncher to get rid of this message.", + "Dalamud is reporting your FFXIV installation has modified game files. Mare Synchronos, Penumbra, and some other plugins assume your FFXIV installation " + + "is unmodified in order to work. Synchronization with pairs/shells can break because of this. Exit the game, open XIVLauncher, click the arrow next to Log " + + "In and select 'repair game files' to resolve this issue. Plugin configurations will remain, as will mods enabled in Penumbra.", NotificationType.Error, TimeSpan.FromSeconds(15))); }