update settings ui character management

This commit is contained in:
Stanley Dimant
2025-02-17 13:01:13 +01:00
parent 61b6365542
commit bfa41fdd96
5 changed files with 142 additions and 65 deletions

View File

@@ -8,4 +8,5 @@ public record Authentication
public int SecretKeyIdx { get; set; } = -1; public int SecretKeyIdx { get; set; } = -1;
public string? UID { get; set; } public string? UID { get; set; }
public bool AutoLogin { get; set; } = true; public bool AutoLogin { get; set; } = true;
public ulong? LastSeenCID { get; set; } = null;
} }

View File

@@ -270,6 +270,18 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber
return await RunOnFrameworkThread(GetPlayerName).ConfigureAwait(false); return await RunOnFrameworkThread(GetPlayerName).ConfigureAwait(false);
} }
public async Task<ulong> GetCIDAsync()
{
return await RunOnFrameworkThread(GetCID).ConfigureAwait(false);
}
public unsafe ulong GetCID()
{
EnsureIsOnFramework();
var playerChar = GetPlayerCharacter();
return ((BattleChara*)playerChar.Address)->Character.ContentId;
}
public async Task<string> GetPlayerNameHashedAsync() public async Task<string> GetPlayerNameHashedAsync()
{ {
return await RunOnFrameworkThread(() => GetHashedAccIdFromPlayerPointer(GetPlayerPointer())).ConfigureAwait(false); return await RunOnFrameworkThread(() => GetHashedAccIdFromPlayerPointer(GetPlayerPointer())).ConfigureAwait(false);

View File

@@ -100,6 +100,7 @@ public class ServerConfigurationManager
var charaName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(); var charaName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult();
var worldId = _dalamudUtil.GetHomeWorldIdAsync().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); var auth = currentServer.Authentications.FindAll(f => string.Equals(f.CharacterName, charaName) && f.WorldId == worldId);
if (auth.Count >= 2) if (auth.Count >= 2)
@@ -115,6 +116,13 @@ public class ServerConfigurationManager
return null; 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)) 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); _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 charaName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult();
var worldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(); var worldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult();
var cid = _dalamudUtil.GetCIDAsync().GetAwaiter().GetResult();
if (!currentServer.Authentications.Any() && currentServer.SecretKeys.Any()) if (!currentServer.Authentications.Any() && currentServer.SecretKeys.Any())
{ {
currentServer.Authentications.Add(new Authentication() currentServer.Authentications.Add(new Authentication()
{ {
CharacterName = charaName, CharacterName = charaName,
WorldId = worldId, WorldId = worldId,
LastSeenCID = cid,
SecretKeyIdx = currentServer.SecretKeys.Last().Key, SecretKeyIdx = currentServer.SecretKeys.Last().Key,
}); });
@@ -165,6 +175,13 @@ public class ServerConfigurationManager
return null; 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)) 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); _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(), CharacterName = _dalamudUtil.GetPlayerNameAsync().GetAwaiter().GetResult(),
WorldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(), WorldId = _dalamudUtil.GetHomeWorldIdAsync().GetAwaiter().GetResult(),
SecretKeyIdx = !server.UseOAuth2 ? server.SecretKeys.Last().Key : -1, SecretKeyIdx = !server.UseOAuth2 ? server.SecretKeys.Last().Key : -1,
LastSeenCID = _dalamudUtil.GetCIDAsync().GetAwaiter().GetResult()
}); });
Save(); Save();
} }

View File

@@ -1,5 +1,6 @@
using Dalamud.Interface; using Dalamud.Interface;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Utility; using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Utility; using Dalamud.Utility;
@@ -29,6 +30,7 @@ using System.Globalization;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Numerics; using System.Numerics;
using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
@@ -65,6 +67,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
private CancellationTokenSource? _validationCts; private CancellationTokenSource? _validationCts;
private Task<List<FileCacheEntity>>? _validationTask; private Task<List<FileCacheEntity>>? _validationTask;
private bool _wasOpen = false; private bool _wasOpen = false;
public SettingsUi(ILogger<SettingsUi> logger, public SettingsUi(ILogger<SettingsUi> logger,
UiSharedService uiShared, MareConfigService configService, UiSharedService uiShared, MareConfigService configService,
PairManager pairManager, 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); " Make sure to enter the character names correctly or use the 'Add current character' button at the bottom.", ImGuiColors.DalamudYellow);
int i = 0; int i = 0;
_uiShared.DrawUpdateOAuthUIDsButton(selectedServer); _uiShared.DrawUpdateOAuthUIDsButton(selectedServer);
if (selectedServer.UseOAuth2 && !string.IsNullOrEmpty(selectedServer.OAuthToken)) if (selectedServer.UseOAuth2 && !string.IsNullOrEmpty(selectedServer.OAuthToken))
{ {
bool hasSetSecretKeysButNoUid = selectedServer.Authentications.Exists(u => u.SecretKeyIdx != -1 && string.IsNullOrEmpty(u.UID)); bool hasSetSecretKeysButNoUid = selectedServer.Authentications.Exists(u => u.SecretKeyIdx != -1 && string.IsNullOrEmpty(u.UID));
@@ -1452,6 +1456,35 @@ public class SettingsUi : WindowMediatorSubscriberBase
} }
} }
ImGui.Separator(); 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()) foreach (var item in selectedServer.Authentications.ToList())
{ {
using var charaId = ImRaii.PushId("selectedChara" + i); using var charaId = ImRaii.PushId("selectedChara" + i);
@@ -1463,8 +1496,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
worldPreview = data.First().Value; worldPreview = data.First().Value;
} }
var friendlyName = string.Empty;
string friendlyNameTranslation = string.Empty;
Dictionary<int, SecretKey> keys = []; Dictionary<int, SecretKey> keys = [];
if (!useOauth) if (!useOauth)
@@ -1475,19 +1506,11 @@ public class SettingsUi : WindowMediatorSubscriberBase
{ {
secretKey = new(); secretKey = new();
} }
friendlyName = secretKey.FriendlyName;
friendlyNameTranslation = "Secret Key";
}
else
{
friendlyName = item.UID ?? "-";
friendlyNameTranslation = "UID";
} }
bool thisIsYou = false; bool thisIsYou = false;
if (string.Equals(_dalamudUtilService.GetPlayerName(), item.CharacterName, StringComparison.OrdinalIgnoreCase) if (string.Equals(youName, item.CharacterName, StringComparison.OrdinalIgnoreCase)
&& _dalamudUtilService.GetWorldId() == worldIdx) && youWorld == worldIdx)
{ {
thisIsYou = true; thisIsYou = true;
} }
@@ -1500,61 +1523,84 @@ public class SettingsUi : WindowMediatorSubscriberBase
{ {
misManaged = true; 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; text += " [MISMANAGED (" + (selectedServer.UseOAuth2 ? "No UID Set" : "No Secret Key Set") + ")]";
if (ImGui.InputText("Character Name", ref charaName, 64)) color = ImGuiColors.DalamudRed;
{ }
item.CharacterName = charaName; if (selectedServer.Authentications.Where(e => e != item).Any(e => string.Equals(e.CharacterName, item.CharacterName, StringComparison.Ordinal)
_serverConfigurationManager.Save(); && e.WorldId == item.WorldId))
} {
text += " [DUPLICATE]";
_uiShared.DrawCombo("World##" + item.CharacterName + i, data, (w) => w.Value, color = ImGuiColors.DalamudRed;
(w) =>
{
if (item.WorldId != w.Key)
{
item.WorldId = w.Key;
_serverConfigurationManager.Save();
}
}, EqualityComparer<KeyValuePair<ushort, string>>.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<KeyValuePair<int, SecretKey>>.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();
} }
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<KeyValuePair<ushort, string>>.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<KeyValuePair<int, SecretKey>>.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++; i++;
if (item != selectedServer.Authentications.ToList()[^1])
{
ImGuiHelpers.ScaledDummy(5);
ImGui.Separator();
ImGuiHelpers.ScaledDummy(5);
}
} }
ImGui.Separator(); if (selectedServer.Authentications.Any())
if (!selectedServer.Authentications.Exists(c => string.Equals(c.CharacterName, _uiShared.PlayerName, StringComparison.Ordinal) ImGui.Separator();
&& c.WorldId == _uiShared.WorldId))
if (!selectedServer.Authentications.Exists(c => string.Equals(c.CharacterName, youName, StringComparison.Ordinal)
&& c.WorldId == youWorld))
{ {
if (_uiShared.IconTextButton(FontAwesomeIcon.User, "Add current character")) if (_uiShared.IconTextButton(FontAwesomeIcon.User, "Add current character"))
{ {
@@ -1624,7 +1670,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndTabItem(); ImGui.EndTabItem();
} }
if (ImGui.BeginTabItem("Service Settings")) if (ImGui.BeginTabItem("Service Configuration"))
{ {
var serverName = selectedServer.ServerName; var serverName = selectedServer.ServerName;
var serverUri = selectedServer.ServerUri; var serverUri = selectedServer.ServerUri;

View File

@@ -261,9 +261,9 @@ public sealed partial class ApiController : DisposableMediatorSubscriberBase, IM
Logger.LogError("Detected modified game files on connection"); Logger.LogError("Detected modified game files on connection");
if (!_mareConfigService.Current.DebugStopWhining) if (!_mareConfigService.Current.DebugStopWhining)
Mediator.Publish(new NotificationMessage("Modified Game Files detected", Mediator.Publish(new NotificationMessage("Modified Game Files detected",
"Dalamud has reported modified game files in your FFXIV installation. " + "Dalamud is reporting your FFXIV installation has modified game files. Mare Synchronos, Penumbra, and some other plugins assume your FFXIV installation " +
"You will be able to connect, but the synchronization functionality might be (partially) broken. " + "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 " +
"Exit the game and repair it through XIVLauncher to get rid of this message.", "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))); NotificationType.Error, TimeSpan.FromSeconds(15)));
} }