Better identity promotion

This commit is contained in:
r00telement
2021-12-27 17:13:51 +00:00
parent 70ccc47984
commit 0026965c32
9 changed files with 219 additions and 210 deletions

View File

@@ -56,6 +56,9 @@ namespace PlayerTags.Configuration
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
public List<Dictionary<string, InheritableData>> CustomTagsChanges = new List<Dictionary<string, InheritableData>>();
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
public List<Identity> Identities = new List<Identity>();
public event System.Action? Saved;
public void Save(PluginData pluginData)
@@ -151,6 +154,8 @@ namespace PlayerTags.Configuration
CustomTagsChanges.Add(customTag.GetChanges());
}
Identities = pluginData.Identities;
PluginServices.DalamudPluginInterface.SavePluginConfig(this);
Saved?.Invoke();
}

View File

@@ -135,7 +135,7 @@ namespace PlayerTags.Configuration
.Where(gameObject => gameObject is PlayerCharacter)
.Select(gameObject => gameObject as PlayerCharacter)
.ToDictionary(
playerCharacter => Identity.From(playerCharacter!),
playerCharacter => m_PluginData.GetIdentity(playerCharacter!),
playerCharacter => new PlayerInfo()
{
PlayerContext = PlayerContextHelper.GetPlayerContext(playerCharacter!),
@@ -145,7 +145,7 @@ namespace PlayerTags.Configuration
// Include party members that aren't in the game object list
foreach (var partyMember in PluginServices.PartyList)
{
var partyMemberIdentity = Identity.From(partyMember);
var partyMemberIdentity = m_PluginData.GetIdentity(partyMember);
if (!playerNameContexts.ContainsKey(partyMemberIdentity))
{
@@ -203,7 +203,7 @@ namespace PlayerTags.Configuration
ImGui.TableHeadersRow();
int rowIndex = 0;
foreach (var identity in m_PluginData.CustomTags.SelectMany(customTag => customTag.IdentitiesToAddTo).Distinct().OrderBy(name => name))
foreach (var identity in m_PluginData.Identities.ToArray())
{
DrawQuickAddRow(identity, rowIndex);
++rowIndex;
@@ -211,7 +211,7 @@ namespace PlayerTags.Configuration
if (PluginServices.ObjectTable.Length == 0 && PluginServices.ClientState.LocalPlayer != null)
{
DrawQuickAddRow(Identity.From(PluginServices.ClientState.LocalPlayer), 0);
DrawQuickAddRow(m_PluginData.GetIdentity(PluginServices.ClientState.LocalPlayer), 0);
}
ImGui.EndTable();
@@ -262,20 +262,20 @@ namespace PlayerTags.Configuration
ImGui.TableNextColumn();
bool isTagAssigned = customTag.CanAddToIdentity(identity);
bool isTagAssigned = identity.CustomTagIds.Contains(customTag.CustomId.Value);
DrawSimpleCheckbox(string.Format(Strings.Loc_Static_Format_AddTagToPlayer, customTag.Text.InheritedValue, identity.Name), ref isTagAssigned, () =>
{
if (isTagAssigned)
{
customTag.AddIdentityToAddTo(identity);
m_PluginData.AddCustomTagToIdentity(customTag, identity);
m_PluginConfiguration.Save(m_PluginData);
}
else
{
customTag.RemoveIdentityToAddTo(identity);
m_PluginData.RemoveCustomTagFromIdentity(customTag, identity);
m_PluginConfiguration.Save(m_PluginData);
}
m_PluginConfiguration.Save(m_PluginData);
});
ImGui.PopID();
@@ -378,7 +378,7 @@ namespace PlayerTags.Configuration
{
IsExpanded = true,
Text = Strings.Loc_Static_NewTag,
GameObjectNamesToApplyTo = ""
CustomId = Guid.NewGuid()
};
m_PluginData.CustomTags.Add(newTag);
@@ -413,6 +413,7 @@ namespace PlayerTags.Configuration
ImGui.SetCursorPosX(ImGui.GetCursorPos().X + ImGui.GetContentRegionAvail().X - 23);
if (ImGui.Button(FontAwesomeIcon.TrashAlt.ToIconString()))
{
m_PluginData.RemoveCustomTagFromIdentities(tag);
m_PluginData.AllCustomTags.Children.Remove(tag);
m_PluginData.CustomTags.Remove(tag);
m_PluginConfiguration.Save(m_PluginData);

View File

@@ -1,23 +1,20 @@
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Party;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Lumina.Excel.GeneratedSheets;
using Lumina.Excel.GeneratedSheets;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace PlayerTags.Data
{
// FirstName LastName
// FirstName LastName@World
// FirstName LastName:Id
// FirstName LastName@World:Id
public struct Identity : IComparable<Identity>, IEquatable<Identity>
[Serializable]
public class Identity : IComparable<Identity>
{
public string Name;
public uint? WorldId;
public string? Id;
public List<Guid> CustomTagIds = new List<Guid>();
[JsonIgnore]
public string? World
{
get
@@ -40,63 +37,10 @@ namespace PlayerTags.Data
}
}
private static Regex s_WorldRegex = new Regex(@"@([a-zA-Z0-9]+)");
private static Regex s_IdRegex = new Regex(@"@([a-zA-Z0-9]+)");
public Identity(string name)
{
Name = name;
WorldId = null;
Id = null;
}
public static Identity From(string str)
{
var identity = new Identity();
while (s_WorldRegex.Match(str) is Match match && match.Success)
{
if (uint.TryParse(match.Groups.Values.Last().Value, out var value))
{
identity.WorldId = value;
}
str = str.Replace(match.Value, "");
}
while (s_IdRegex.Match(str) is Match match && match.Success)
{
identity.Id = match.Groups.Values.Last().Value;
str = str.Replace(match.Value, "");
}
identity.Name = str;
return identity;
}
public static Identity From(PlayerCharacter playerCharacter)
{
return new Identity(playerCharacter.Name.TextValue)
{
WorldId = playerCharacter.HomeWorld.GameData.RowId
};
}
public static Identity From(PartyMember partyMember)
{
return new Identity(partyMember.Name.TextValue)
{
WorldId = partyMember.World.GameData.RowId
};
}
public static Identity From(PlayerPayload playerPayload)
{
return new Identity(playerPayload.PlayerName)
{
WorldId = playerPayload.World.RowId
};
}
public override string ToString()
@@ -108,76 +52,18 @@ namespace PlayerTags.Data
str += $"@{World}";
}
if (Id != null)
{
str += $":{Id}";
}
return str;
}
public string ToDataString()
public int CompareTo(Identity? other)
{
string str = Name;
if (WorldId != null)
string? otherName = null;
if (other != null)
{
str += $"@{WorldId}";
otherName = other.Name;
}
if (Id != null)
{
str += $":{Id}";
}
return str;
}
public override bool Equals(object? obj)
{
return obj is Identity identity && Equals(identity);
}
public bool Equals(Identity obj)
{
return this == obj;
}
public static bool operator ==(Identity first, Identity second)
{
if (first.Id != null || second.Id != null)
{
return first.Id == second.Id;
}
bool areNamesEqual = first.Name.ToLower().Trim() == second.Name.ToLower().Trim();
// If one of the worlds are null then it's technically equal as it could be promoted to the identity that does have a world
bool areWorldsEqual = first.WorldId == null || second.WorldId == null || first.WorldId == second.WorldId;
return areNamesEqual && areWorldsEqual;
}
public static bool operator !=(Identity first, Identity second)
{
return !(first == second);
}
public override int GetHashCode()
{
var hashCode = Name.GetHashCode();
if (Id != null)
{
hashCode *= 17 ^ Id.GetHashCode();
}
return hashCode;
}
public int CompareTo(Identity other)
{
return Name.CompareTo(other.Name);
return Name.CompareTo(otherName);
}
}
}

View File

@@ -1,7 +1,12 @@
using PlayerTags.Configuration;
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Party;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using PlayerTags.Configuration;
using PlayerTags.PluginStrings;
using System;
using System.Collections.Generic;
using System.Linq;
using XivCommon.Functions.ContextMenu;
namespace PlayerTags.Data
{
@@ -17,9 +22,14 @@ namespace PlayerTags.Data
public Dictionary<string, Tag> JobTags;
public Tag AllCustomTags;
public List<Tag> CustomTags;
public List<Identity> Identities;
private PluginConfiguration m_PluginConfiguration;
public PluginData(PluginConfiguration pluginConfiguration)
{
m_PluginConfiguration = pluginConfiguration;
Default = new DefaultPluginData();
// Set the default changes and saved changes
@@ -166,6 +176,132 @@ namespace PlayerTags.Data
{
tag.Parent = AllCustomTags;
}
Identities = pluginConfiguration.Identities;
// Migrate old custom tag identity assignments
bool customTagsMigrated = false;
foreach (var customTag in CustomTags)
{
if (customTag.CustomId.Value == Guid.Empty)
{
customTag.CustomId.Behavior = Inheritables.InheritableBehavior.Enabled;
customTag.CustomId.Value = Guid.NewGuid();
customTagsMigrated = true;
}
foreach (string identityToAddTo in customTag.IdentitiesToAddTo)
{
Identity? identity = Identities.FirstOrDefault(identity => identity.Name.ToLower() == identityToAddTo.ToLower());
if (identity == null)
{
identity = new Identity(identityToAddTo);
Identities.Add(identity);
}
if (identity != null)
{
identity.CustomTagIds.Add(customTag.CustomId.Value);
customTagsMigrated = true;
}
}
if (customTag.GameObjectNamesToApplyTo.Behavior != Inheritables.InheritableBehavior.Inherit)
{
customTag.GameObjectNamesToApplyTo.Behavior = Inheritables.InheritableBehavior.Inherit;
customTag.GameObjectNamesToApplyTo.Value = "";
customTagsMigrated = true;
}
}
if (customTagsMigrated)
{
pluginConfiguration.Save(this);
}
}
public void AddCustomTagToIdentity(Tag customTag, Identity identity)
{
if (!identity.CustomTagIds.Contains(customTag.CustomId.Value))
{
identity.CustomTagIds.Add(customTag.CustomId.Value);
}
if (!Identities.Contains(identity))
{
Identities.Add(identity);
}
}
public void RemoveCustomTagFromIdentity(Tag customTag, Identity identity)
{
identity.CustomTagIds.Remove(customTag.CustomId.Value);
if (!identity.CustomTagIds.Any())
{
Identities.Remove(identity);
}
}
public void RemoveCustomTagFromIdentities(Tag customTag)
{
foreach (var identity in Identities)
{
RemoveCustomTagFromIdentity(customTag, identity);
}
}
public Identity GetIdentity(string name, uint? worldId)
{
foreach (var identity in Identities)
{
if (identity.Name.ToLower().Trim() == name.ToLower().Trim())
{
if (identity.WorldId == null && worldId != null)
{
identity.WorldId = worldId;
m_PluginConfiguration.Save(this);
return identity;
}
else
{
return identity;
}
}
}
return new Identity(name)
{
WorldId = worldId
};
}
public Identity? GetIdentity(ContextMenuOpenArgs contextMenuOpenArgs)
{
if (contextMenuOpenArgs.Text == null
|| contextMenuOpenArgs.ObjectWorld == 0
|| contextMenuOpenArgs.ObjectWorld == 65535)
{
return null;
}
return GetIdentity(contextMenuOpenArgs.Text!.TextValue, contextMenuOpenArgs.ObjectWorld);
}
public Identity GetIdentity(PlayerCharacter playerCharacter)
{
return GetIdentity(playerCharacter.Name.TextValue, playerCharacter.HomeWorld.GameData.RowId);
}
public Identity GetIdentity(PartyMember partyMember)
{
return GetIdentity(partyMember.Name.TextValue, partyMember.World.GameData.RowId);
}
public Identity GetIdentity(PlayerPayload playerPayload)
{
return GetIdentity(playerPayload.PlayerName, playerPayload.World.RowId);
}
}
}

View File

@@ -91,8 +91,12 @@ namespace PlayerTags.Data
Behavior = InheritableBehavior.Enabled
};
// Deprecated
[InheritableCategory("General")]
public InheritableReference<string> GameObjectNamesToApplyTo = new InheritableReference<string>("");
public InheritableValue<Guid> CustomId = new InheritableValue<Guid>(Guid.Empty);
[InheritableCategory("IconCategory")]
public InheritableValue<BitmapFontIcon> Icon = new InheritableValue<BitmapFontIcon>(BitmapFontIcon.Aethernet);
[InheritableCategory("IconCategory")]
@@ -148,7 +152,7 @@ namespace PlayerTags.Data
[InheritableCategory("PlayerCategory")]
public InheritableValue<bool> IsVisibleForOtherPlayers = new InheritableValue<bool>(false);
private string[] IdentityDatasToAddTo
public string[] IdentitiesToAddTo
{
get
{
@@ -161,14 +165,6 @@ namespace PlayerTags.Data
}
}
public Identity[] IdentitiesToAddTo
{
get
{
return IdentityDatasToAddTo.Select(identityData => Identity.From(identityData)).ToArray();
}
}
private Tag? m_Defaults;
public bool HasDefaults
{
@@ -194,31 +190,6 @@ namespace PlayerTags.Data
SetChanges(defaults.GetChanges());
}
public bool CanAddToIdentity(Identity identity)
{
return IdentitiesToAddTo.Contains(identity);
}
public void AddIdentityToAddTo(Identity identity)
{
if (CanAddToIdentity(identity))
{
return;
}
GameObjectNamesToApplyTo.Value = string.Join(", ", IdentitiesToAddTo.Append(identity).Select(id => id.ToDataString()));
}
public void RemoveIdentityToAddTo(Identity identity)
{
if (!CanAddToIdentity(identity))
{
return;
}
GameObjectNamesToApplyTo.Value = string.Join(", ", IdentitiesToAddTo.Where(identityToAddTo => identityToAddTo != identity).Select(id => id.ToDataString()));
}
public Dictionary<string, InheritableData> GetChanges(Dictionary<string, InheritableData>? defaultChanges = null)
{
Dictionary<string, InheritableData> changes = new Dictionary<string, InheritableData>();

View File

@@ -205,12 +205,14 @@ namespace PlayerTags.Features
}
}
// Add custom tags
if (stringMatch.PlayerPayload != null)
{
// Add all other tags
foreach (var customTag in m_PluginData.CustomTags)
Identity identity = m_PluginData.GetIdentity(stringMatch.PlayerPayload);
foreach (var customTagId in identity.CustomTagIds)
{
if (customTag.CanAddToIdentity(Identity.From(stringMatch.PlayerPayload)))
var customTag = m_PluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
if (customTag != null)
{
if (customTag.TagPositionInChat.InheritedValue != null)
{
@@ -227,9 +229,11 @@ namespace PlayerTags.Features
// An additional step to apply text color to additional locations
if (stringMatch.PlayerPayload != null && stringMatch.PreferredPayload != null)
{
foreach (var customTag in m_PluginData.CustomTags)
Identity identity = m_PluginData.GetIdentity(stringMatch.PlayerPayload);
foreach (var customTagId in identity.CustomTagIds)
{
if (customTag.CanAddToIdentity(Identity.From(stringMatch.PlayerPayload)))
var customTag = m_PluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
if (customTag != null)
{
if (IsTagVisible(customTag, stringMatch.GameObject))
{

View File

@@ -52,42 +52,40 @@ namespace PlayerTags.Features
return;
}
var identity = new Identity()
Identity? identity = m_PluginData.GetIdentity(args);
if (identity != null)
{
Name = args.Text!.TextValue,
WorldId = args.ObjectWorld
};
var notAddedTags = m_PluginData.CustomTags.Where(tag => !tag.CanAddToIdentity(identity));
if (notAddedTags.Any())
{
args.Items.Add(new NormalContextSubMenuItem(Strings.Loc_Static_ContextMenu_AddTag, (itemArgs =>
var notAddedTags = m_PluginData.CustomTags.Where(customTag => !identity.CustomTagIds.Contains(customTag.CustomId.Value));
if (notAddedTags.Any())
{
foreach (var notAddedTag in notAddedTags)
args.Items.Add(new NormalContextSubMenuItem(Strings.Loc_Static_ContextMenu_AddTag, (itemArgs =>
{
itemArgs.Items.Add(new NormalContextMenuItem(notAddedTag.Text.Value, (args =>
foreach (var notAddedTag in notAddedTags)
{
notAddedTag.AddIdentityToAddTo(identity);
m_PluginConfiguration.Save(m_PluginData);
})));
}
})));
}
itemArgs.Items.Add(new NormalContextMenuItem(notAddedTag.Text.Value, (args =>
{
m_PluginData.AddCustomTagToIdentity(notAddedTag, identity);
m_PluginConfiguration.Save(m_PluginData);
})));
}
})));
}
var addedTags = m_PluginData.CustomTags.Where(tag => tag.CanAddToIdentity(identity));
if (addedTags.Any())
{
args.Items.Add(new NormalContextSubMenuItem(Strings.Loc_Static_ContextMenu_RemoveTag, (itemArgs =>
var addedTags = m_PluginData.CustomTags.Where(customTag => identity.CustomTagIds.Contains(customTag.CustomId.Value));
if (addedTags.Any())
{
foreach (var addedTag in addedTags)
args.Items.Add(new NormalContextSubMenuItem(Strings.Loc_Static_ContextMenu_RemoveTag, (itemArgs =>
{
itemArgs.Items.Add(new NormalContextMenuItem(addedTag.Text.Value, (args =>
foreach (var addedTag in addedTags)
{
addedTag.RemoveIdentityToAddTo(identity);
m_PluginConfiguration.Save(m_PluginData);
})));
}
})));
itemArgs.Items.Add(new NormalContextMenuItem(addedTag.Text.Value, (args =>
{
m_PluginData.RemoveCustomTagFromIdentity(addedTag, identity);
m_PluginConfiguration.Save(m_PluginData);
})));
}
})));
}
}
}

View File

@@ -204,10 +204,12 @@ namespace PlayerTags.Features
}
}
// Add all other tags
foreach (var customTag in m_PluginData.CustomTags)
// Add custom tags
Identity identity = m_PluginData.GetIdentity(playerCharacter);
foreach (var customTagId in identity.CustomTagIds)
{
if (customTag.CanAddToIdentity(Identity.From(playerCharacter)))
var customTag = m_PluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
if (customTag != null)
{
if (customTag.TagTargetInNameplates.InheritedValue != null && customTag.TagPositionInNameplates.InheritedValue != null)
{
@@ -250,9 +252,11 @@ namespace PlayerTags.Features
if (gameObject is PlayerCharacter playerCharacter1)
{
// An additional step to apply text color to additional locations
foreach (var customTag in m_PluginData.CustomTags)
Identity identity = m_PluginData.GetIdentity(playerCharacter1);
foreach (var customTagId in identity.CustomTagIds)
{
if (customTag.CanAddToIdentity(Identity.From(playerCharacter1)))
var customTag = m_PluginData.CustomTags.FirstOrDefault(tag => tag.CustomId.Value == customTagId);
if (customTag != null)
{
if (IsTagVisible(customTag, gameObject))
{

View File

@@ -67,6 +67,10 @@ namespace PlayerTags.Inheritables
// This should never happen
PluginLog.Error($"Expected value of type {Value.GetType()} but received null");
}
else if (typeof(T) == typeof(Guid) && inheritableData.Value is string strValue)
{
Value = (T)(object)Guid.Parse(strValue);
}
else
{
Value = (T)Convert.ChangeType(inheritableData.Value, typeof(T));