diff --git a/PlayerTags.sln b/PlayerTags.sln index a1c7ff1..c058c5e 100644 --- a/PlayerTags.sln +++ b/PlayerTags.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29709.97 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayerTags", "PlayerTags\PlayerTags.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlayerTags", "PlayerTags\PlayerTags.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/PlayerTags/Config/CustomColorConfig.cs b/PlayerTags/Config/CustomColorConfig.cs deleted file mode 100644 index f73595b..0000000 --- a/PlayerTags/Config/CustomColorConfig.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PlayerTags.Config -{ - public class CustomColorConfig - { - public ushort? Id = null; - } -} diff --git a/PlayerTags/Config/CustomTagConfig.cs b/PlayerTags/Config/CustomTagConfig.cs deleted file mode 100644 index 5b0990b..0000000 --- a/PlayerTags/Config/CustomTagConfig.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Linq; - -namespace PlayerTags.Config -{ - [Serializable] - public class CustomTagConfig : TagConfig - { - public CustomColorConfig CustomColor = new CustomColorConfig(); - public string Name = ""; - public string FormattedGameObjectNames = ""; - - private string[] GameObjectNames - { - get - { - return FormattedGameObjectNames.Split(';').Select(gameObjectName => gameObjectName.ToLower().Trim()).ToArray(); - } - } - - public bool IncludesGameObjectName(string gameObjectName) - { - return GameObjectNames.Contains(gameObjectName); - } - } -} diff --git a/PlayerTags/Config/FreeCompanyNameplateVisibility.cs b/PlayerTags/Config/FreeCompanyNameplateVisibility.cs deleted file mode 100644 index 927bcb7..0000000 --- a/PlayerTags/Config/FreeCompanyNameplateVisibility.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PlayerTags.Config -{ - public enum FreeCompanyNameplateVisibility - { - Default, - Never - } -} diff --git a/PlayerTags/Config/JobOverrideConfig.cs b/PlayerTags/Config/JobOverrideConfig.cs deleted file mode 100644 index 3907614..0000000 --- a/PlayerTags/Config/JobOverrideConfig.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace PlayerTags.Config -{ - [Serializable] - public class JobOverrideConfig - { - public CustomColorConfig CustomColor = new CustomColorConfig(); - } -} diff --git a/PlayerTags/Config/MainConfig.cs b/PlayerTags/Config/MainConfig.cs deleted file mode 100644 index bc6067a..0000000 --- a/PlayerTags/Config/MainConfig.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Dalamud.Configuration; -using Dalamud.Data; -using Dalamud.Plugin; -using Lumina.Excel.GeneratedSheets; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace PlayerTags.Config -{ - [Serializable] - public class MainConfig : IPluginConfiguration - { - public static Dictionary RolesById { get; } = new Dictionary() - { - { 0, Role.LandHand }, - { 1, Role.Tank }, - { 2, Role.DPS }, - { 3, Role.DPS }, - { 4, Role.Healer }, - }; - - public int Version { get; set; } = 0; - - public FreeCompanyNameplateVisibility FreeCompanyVisibility = FreeCompanyNameplateVisibility.Default; - public TitleNameplateVisibility TitleVisibility = TitleNameplateVisibility.Default; - public TitleNameplatePosition TitlePosition = TitleNameplatePosition.Default; - - public RoleTagConfig RoleTag = new RoleTagConfig(); - - public List CustomTagConfigs = new List(); - - public bool IsPlayerNameRandomlyGenerated = false; - - [NonSerialized] - private DalamudPluginInterface? m_PluginInterface; - - public event System.Action? Saved; - - public void Initialize(DalamudPluginInterface pluginInterface, DataManager dataManager) - { - m_PluginInterface = pluginInterface; - - // Populate each role config with all of its jobs if they aren't already in it - foreach (var roleConfigPair in RoleTag.RoleOverrideConfigs) - { - var role = roleConfigPair.Key; - var roleConfig = roleConfigPair.Value; - - var classJobs = dataManager.GetExcelSheet(); - if (classJobs != null) - { - foreach (var classJob in classJobs.Where(classJob => RolesById[classJob.Role] == role)) - { - if (!roleConfig.JobOverrideConfigs.ContainsKey(classJob.Abbreviation)) - { - roleConfig.JobOverrideConfigs[classJob.Abbreviation] = new JobOverrideConfig(); - } - } - } - } - } - - public void Save() - { - if (m_PluginInterface != null) - { - m_PluginInterface.SavePluginConfig(this); - Saved?.Invoke(); - }; - } - } -} diff --git a/PlayerTags/Config/MainConfigUI.cs b/PlayerTags/Config/MainConfigUI.cs deleted file mode 100644 index e692cad..0000000 --- a/PlayerTags/Config/MainConfigUI.cs +++ /dev/null @@ -1,403 +0,0 @@ -using Dalamud.Interface.Components; -using Dalamud.Logging; -using ImGuiNET; -using Lumina.Excel.GeneratedSheets; -using PlayerTags.Resources; -using System; -using System.Linq; -using System.Numerics; - -namespace PlayerTags.Config -{ - public class MainConfigUI - { - private MainConfig m_Config; - - private bool m_OpenPopupRequested; - - private CustomColorConfig? m_ColorPickerPopupDataContext; - - private bool m_IsVisible = false; - public bool IsVisible - { - get { return m_IsVisible; } - set { m_IsVisible = value; } - } - - public MainConfigUI(MainConfig config) - { - m_Config = config; - } - - private string GetLocString(bool isDescription) - where TEnum : Enum - { - return GetLocString(typeof(TEnum).Name, isDescription); - } - - private string GetLocString(TEnum enumValue, bool isDescription) - where TEnum : Enum - { - return GetLocString($"{typeof(TEnum).Name}_{enumValue}", isDescription); - } - - private string GetLocString(string locStringId, bool isDescription) - { - string completeLocStringId = $"Loc_{locStringId}"; - - if (isDescription) - { - completeLocStringId += "_Description"; - } - - return GetLocString(completeLocStringId); - } - - private string GetLocString(string completeLocStringId) - { - string? value = Strings.ResourceManager.GetString(completeLocStringId, Strings.Culture); - if (value != null) - { - return value; - } - - PluginLog.Error($"Failed to get localized string for id {completeLocStringId}"); - return completeLocStringId; - } - - public void Draw() - { - if (m_Config == null || !IsVisible) - { - return; - } - - if (ImGui.Begin(Strings.Loc_Static_PluginName, ref m_IsVisible)) - { - if (ImGui.BeginTabBar("MainTabBar")) - { - if (ImGui.BeginTabItem(Strings.Loc_Static_General)) - { - DrawHeading(Strings.Loc_Static_Nameplates); - DrawEnumComboBox( - ref m_Config.FreeCompanyVisibility, - () => m_Config.Save()); - DrawEnumComboBox( - ref m_Config.TitleVisibility, - () => m_Config.Save()); - DrawEnumComboBox( - ref m_Config.TitlePosition, - () => m_Config.Save()); - DrawHeading(Strings.Loc_Static_Development); - DrawCheckbox( - nameof(m_Config.IsPlayerNameRandomlyGenerated), - ref m_Config.IsPlayerNameRandomlyGenerated, - () => m_Config.Save()); - - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem(Strings.Loc_Static_RoleAndJobTags)) - { - DrawEnumComboBox( - ref m_Config.RoleTag.Format, - () => m_Config.Save()); - DrawTagConfig(m_Config.RoleTag); - - DrawHeading(Strings.Loc_Static_Roles); - if (ImGui.BeginTabBar("JobAndRolesTabBar")) - { - foreach (var rolePair in m_Config.RoleTag.RoleOverrideConfigs) - { - var role = rolePair.Key; - var roleConfig = rolePair.Value; - - if (ImGui.BeginTabItem(GetLocString($"{role.GetType().Name}_{role}", false))) - { - DrawCheckbox( - $"{roleConfig.GetType().Name}_{nameof(roleConfig.IsEnabled)}", - ref roleConfig.IsEnabled, - () => m_Config.Save()); - DrawTextBox( - $"{roleConfig.GetType().Name}_{nameof(roleConfig.Name)}", - ref roleConfig.Name, - () => m_Config.Save()); - DrawOptionalCustomColor( - $"{roleConfig.CustomColor.GetType().Name}_IsEnabled", - roleConfig.CustomColor.Id.ToString()!, - roleConfig.CustomColor); - DrawHeading(Strings.Loc_Static_Jobs); - foreach (var key in roleConfig.JobOverrideConfigs.Keys.OrderBy(key => key)) - { - if (string.IsNullOrEmpty(key)) - { - continue; - } - - JobOverrideConfig jobConfig = roleConfig.JobOverrideConfigs[key]; - - ImGui.Columns(2, "columns", false); - ImGui.SetColumnWidth(0, 42); - ImGui.Text(key); - ImGui.NextColumn(); - DrawOptionalCustomColor( - $"{roleConfig.CustomColor.GetType().Name}_IsEnabled", - key, - jobConfig.CustomColor); - - ImGui.Columns(); - } - - ImGui.EndTabItem(); - } - } - - ImGui.EndTabBar(); - } - - ImGui.EndTabItem(); - } - - if (ImGui.BeginTabItem(Strings.Loc_Static_CustomTags)) - { - if (ImGui.Button(Strings.Loc_Static_AddCustomTag)) - { - m_Config.CustomTagConfigs.Add(new CustomTagConfig()); - m_Config.Save(); - } - - if (!m_Config.CustomTagConfigs.Any()) - { - ImGui.Text(Strings.Loc_Static_NoCustomTagsAdded); - } - else - { - foreach (var customTagConfig in m_Config.CustomTagConfigs.ToArray()) - { - ImGui.PushID(customTagConfig.GetHashCode().ToString()); - ImGui.Separator(); - DrawTextBox( - $"{customTagConfig.GetType().Name}_{nameof(customTagConfig.Name)}", - ref customTagConfig.Name, - () => { m_Config.Save(); }); - DrawOptionalCustomColor( - $"{customTagConfig.CustomColor.GetType().Name}_IsEnabled", - customTagConfig.CustomColor.Id.ToString()!, - customTagConfig.CustomColor); - DrawTextBox( - $"{customTagConfig.GetType().Name}_{nameof(customTagConfig.FormattedGameObjectNames)}", - ref customTagConfig.FormattedGameObjectNames, - () => { m_Config.Save(); }); - DrawTagConfig(customTagConfig); - ImGui.Spacing(); - ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.4f, 0.1f, 0.1f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.6f, 0.2f, 0.2f, 1)); - ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.6f, 0.2f, 0.2f, 1)); - if (ImGui.Button(Strings.Loc_Static_RemoveCustomTag)) - { - m_Config.CustomTagConfigs.Remove(customTagConfig); - m_Config.Save(); - } - ImGui.PopStyleColor(); - ImGui.PopStyleColor(); - ImGui.PopStyleColor(); - ImGui.PopID(); - } - } - - ImGui.EndTabItem(); - } - - ImGui.EndTabBar(); - } - - if (m_OpenPopupRequested == true) - { - m_OpenPopupRequested = false; - ImGui.OpenPopup("ColorPickerPopup"); - } - - ImGui.SetNextWindowSize(new Vector2(400, 284)); - if (ImGui.BeginPopup("ColorPickerPopup")) - { - DrawUIColorPicker( - (UIColor value) => - { - if (m_ColorPickerPopupDataContext != null) - { - m_ColorPickerPopupDataContext.Id = (ushort)value.RowId; - m_ColorPickerPopupDataContext = null; - m_Config.Save(); - } - - ImGui.CloseCurrentPopup(); - }); - - ImGui.EndPopup(); - } - - ImGui.End(); - } - } - - private void DrawTagConfig(TagConfig tagConfig) - { - if (m_Config == null || !IsVisible) - { - return; - } - - DrawHeading(Strings.Loc_Static_ChatTag); - ImGui.PushID("Chat"); - DrawEnumComboBox( - ref tagConfig.ChatPosition, - () => m_Config.Save()); - ImGui.PopID(); - DrawHeading(Strings.Loc_Static_NameplateTag); - ImGui.PushID("Nameplate"); - DrawEnumComboBox( - ref tagConfig.NameplatePosition, - () => m_Config.Save()); - DrawEnumComboBox( - ref tagConfig.NameplateElement, - () => m_Config.Save()); - ImGui.PopID(); - } - - private void DrawOptionalCustomColor(string locStringId, string colorId, CustomColorConfig customColorConfig) - { - if (customColorConfig.Id.HasValue) - { - DrawColorButton( - colorId, - UIColorHelper.ToColor(customColorConfig.Id.Value), - () => - { - m_ColorPickerPopupDataContext = customColorConfig; - m_OpenPopupRequested = true; - }); - - ImGui.SameLine(); - } - - var isChecked = customColorConfig.Id != null; - DrawCheckbox( - locStringId, - ref isChecked, - () => - { - if (!isChecked) - { - customColorConfig.Id = null; - m_Config.Save(); - } - else - { - customColorConfig.Id = (ushort)UIColorHelper.UIColors.First().RowId; - m_Config.Save(); - } - }); - } - - private void DrawSeparator() - { - ImGui.Spacing(); - ImGui.Spacing(); - ImGui.Spacing(); - ImGui.Spacing(); - } - - private void DrawHeading(string label) - { - ImGui.TextColored(new Vector4(0.7f, 0.6f, 1f, 1f), label); - } - - private void DrawEnumComboBox(ref TEnum currentValue, System.Action changed) - where TEnum : Enum - { - ImGui.Text(GetLocString(false)); - ImGuiComponents.HelpMarker(GetLocString(true)); - - if (ImGui.BeginCombo($"###{currentValue.GetType().Name}", GetLocString(currentValue, false))) - { - foreach (string enumValueString in typeof(TEnum).GetEnumNames()) - { - TEnum enumValue = (TEnum)Enum.Parse(typeof(TEnum), enumValueString); - bool isSelected = enumValueString == currentValue.ToString(); - if (ImGui.Selectable($"{GetLocString(enumValue, false)}###{enumValueString}", isSelected)) - { - currentValue = (TEnum)Enum.Parse(typeof(TEnum), enumValueString); - ImGui.SetItemDefaultFocus(); - changed(); - } - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(GetLocString(enumValue, true)); - } - } - - ImGui.EndCombo(); - } - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(GetLocString(currentValue, true)); - } - } - - private void DrawCheckbox(string locStringId, ref bool isChecked, System.Action changed) - { - if (ImGui.Checkbox(GetLocString(locStringId, false), ref isChecked)) - { - changed(); - } - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(GetLocString(locStringId, true)); - } - } - - private void DrawColorButton(string colorId, Vector4 color, System.Action clicked) - { - if (ImGui.ColorButton(colorId, color)) - { - clicked(); - } - } - - private void DrawTextBox(string locStringId, ref string text, System.Action changed) - { - ImGui.Text(GetLocString(locStringId, false)); - ImGuiComponents.HelpMarker(GetLocString(locStringId, true)); - - var oldText = text; - ImGui.InputText($"###{locStringId}", ref text, 1024); - if (text != oldText) - { - changed(); - } - } - - private void DrawUIColorPicker(System.Action clicked) - { - ImGui.PushID(clicked.GetHashCode()); - ImGui.Columns(12, "columns", false); - foreach (var uiColor in UIColorHelper.UIColors) - { - DrawColorButton( - uiColor.RowId.ToString(), - UIColorHelper.ToColor(uiColor), - () => - { - clicked(uiColor); - }); - - ImGui.NextColumn(); - } - ImGui.Columns(); - ImGui.PopID(); - } - } -} diff --git a/PlayerTags/Config/RoleOverrideConfig.cs b/PlayerTags/Config/RoleOverrideConfig.cs deleted file mode 100644 index 3c08d4c..0000000 --- a/PlayerTags/Config/RoleOverrideConfig.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PlayerTags.Config -{ - [Serializable] - public class RoleOverrideConfig - { - public bool IsEnabled = true; - public string Name = ""; - public CustomColorConfig CustomColor = new CustomColorConfig(); - public Dictionary JobOverrideConfigs = new Dictionary(); - } -} diff --git a/PlayerTags/Config/RoleTagConfig.cs b/PlayerTags/Config/RoleTagConfig.cs deleted file mode 100644 index 4e6a707..0000000 --- a/PlayerTags/Config/RoleTagConfig.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace PlayerTags.Config -{ - [Serializable] - public class RoleTagConfig : TagConfig - { - public RoleTagFormat Format = RoleTagFormat.AbbreviatedJobName; - - public Dictionary RoleOverrideConfigs = new Dictionary() - { - { Role.LandHand, new RoleOverrideConfig() { IsEnabled = true, Name = "Land/Hand", CustomColor = new CustomColorConfig() { Id = 3 } } }, - { Role.Tank, new RoleOverrideConfig() { IsEnabled = true, Name = "Tank", CustomColor = new CustomColorConfig() { Id = 542 } } }, - { Role.Healer, new RoleOverrideConfig() { IsEnabled = true, Name = "Healer", CustomColor = new CustomColorConfig() { Id = 45 } } }, - { Role.DPS, new RoleOverrideConfig() { IsEnabled = true, Name = "DPS", CustomColor = new CustomColorConfig() { Id = 511 } } }, - }; - } -} diff --git a/PlayerTags/Config/RoleTagFormat.cs b/PlayerTags/Config/RoleTagFormat.cs deleted file mode 100644 index 5e945fe..0000000 --- a/PlayerTags/Config/RoleTagFormat.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PlayerTags.Config -{ - public enum RoleTagFormat - { - AbbreviatedJobName, - JobName, - RoleName - } -} diff --git a/PlayerTags/Config/StringPosition.cs b/PlayerTags/Config/StringPosition.cs deleted file mode 100644 index d076c96..0000000 --- a/PlayerTags/Config/StringPosition.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace PlayerTags.Config -{ - public enum StringPosition - { - None, - Before, - After, - Replace - } -} diff --git a/PlayerTags/Config/TagConfig.cs b/PlayerTags/Config/TagConfig.cs deleted file mode 100644 index bcbc1cb..0000000 --- a/PlayerTags/Config/TagConfig.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace PlayerTags.Config -{ - [Serializable] - public class TagConfig - { - public NameplateElement NameplateElement = NameplateElement.Name; - - public StringPosition NameplatePosition = StringPosition.Before; - - public StringPosition ChatPosition = StringPosition.Before; - } -} diff --git a/PlayerTags/DefaultPluginData.cs b/PlayerTags/DefaultPluginData.cs new file mode 100644 index 0000000..65cf524 --- /dev/null +++ b/PlayerTags/DefaultPluginData.cs @@ -0,0 +1,97 @@ +using Dalamud.Data; +using Dalamud.Game.Text.SeStringHandling; +using Lumina.Excel.GeneratedSheets; +using System.Collections.Generic; +using System.Linq; + +namespace PlayerTags +{ + public class DefaultPluginData + { + public Dictionary RolesById { get; } = new Dictionary() + { + { 0, Role.LandHand }, + { 1, Role.Tank }, + { 2, Role.DPS }, + { 3, Role.DPS }, + { 4, Role.Healer }, + }; + + public Dictionary RolesByJobAbbreviation { get; } = new Dictionary(); + + public Dictionary AllTagsChanges = new Dictionary(); + public Dictionary AllRoleTagsChanges = new Dictionary(); + public Dictionary> RoleTagsChanges = new Dictionary>(); + public Dictionary> JobTagsChanges = new Dictionary>(); + public Dictionary AllCustomTagsChanges = new Dictionary(); + + public void Initialize(DataManager dataManager) + { + AllTagsChanges = new Tag(new LiteralPluginString("")) + { + TagPositionInChat = TagPosition.Before, + TagPositionInNameplates = TagPosition.Replace, + TagTargetInNameplates = NameplateElement.Title, + IsTextItalic = true, + }.GetChanges(); + + AllRoleTagsChanges = new Tag(new LiteralPluginString("")) + { + IsIconVisibleInChat = true, + IsTextVisibleInNameplates = true, + }.GetChanges(); + + RoleTagsChanges[Role.LandHand] = new Tag(new LiteralPluginString("")) + { + Icon = BitmapFontIcon.Crafter, + TextColor = 3, + }.GetChanges(); + + RoleTagsChanges[Role.Tank] = new Tag(new LiteralPluginString("")) + { + Icon = BitmapFontIcon.Tank, + TextColor = 546, + }.GetChanges(); + + RoleTagsChanges[Role.Healer] = new Tag(new LiteralPluginString("")) + { + Icon = BitmapFontIcon.Healer, + TextColor = 43, + }.GetChanges(); + + RoleTagsChanges[Role.DPS] = new Tag(new LiteralPluginString("")) + { + Icon = BitmapFontIcon.DPS, + TextColor = 508, + }.GetChanges(); + + foreach ((var role, var roleTagChanges) in RoleTagsChanges) + { + var classJobs = dataManager.GetExcelSheet(); + if (classJobs == null) + { + break; + } + + foreach (var classJob in classJobs.Where(classJob => RolesById[classJob.Role] == role && !string.IsNullOrEmpty(classJob.Abbreviation.RawString))) + { + RolesByJobAbbreviation[classJob.Abbreviation.RawString] = role; + + if (!JobTagsChanges.ContainsKey(classJob.Abbreviation.RawString)) + { + JobTagsChanges[classJob.Abbreviation.RawString] = new Tag(new LiteralPluginString("")) + { + Text = classJob.Abbreviation.RawString, + }.GetChanges(); + } + } + } + + AllCustomTagsChanges = new Tag(new LiteralPluginString("")) + { + IsTextVisibleInChat = true, + IsTextVisibleInNameplates = true, + }.GetChanges(); + } + } +} diff --git a/PlayerTags/GeneralConverter.cs b/PlayerTags/GeneralConverter.cs new file mode 100644 index 0000000..eca30aa --- /dev/null +++ b/PlayerTags/GeneralConverter.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; +using System; + +namespace PlayerTags +{ + public class GeneralConverter : JsonConverter + { + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value != null && value.GetType().IsEnum) + { + writer.WriteValue(Enum.GetName(value.GetType(), value)); + } + else + { + writer.WriteValue(value); + } + } + + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + return reader.Value; + } + + public override bool CanConvert(Type objectType) + { + return true; + } + } +} diff --git a/PlayerTags/IInheritable.cs b/PlayerTags/IInheritable.cs new file mode 100644 index 0000000..acaa423 --- /dev/null +++ b/PlayerTags/IInheritable.cs @@ -0,0 +1,13 @@ +namespace PlayerTags +{ + public interface IInheritable + { + public IInheritable? Parent { get; set; } + + public InheritableBehavior Behavior { get; set; } + + public abstract void SetData(InheritableData inheritableData); + + public abstract InheritableData GetData(); + } +} diff --git a/PlayerTags/IPluginString.cs b/PlayerTags/IPluginString.cs new file mode 100644 index 0000000..d62f7ca --- /dev/null +++ b/PlayerTags/IPluginString.cs @@ -0,0 +1,7 @@ +namespace PlayerTags +{ + public interface IPluginString + { + public string Value { get; } + } +} diff --git a/PlayerTags/InheritableBehavior.cs b/PlayerTags/InheritableBehavior.cs new file mode 100644 index 0000000..f75b2af --- /dev/null +++ b/PlayerTags/InheritableBehavior.cs @@ -0,0 +1,9 @@ +namespace PlayerTags +{ + public enum InheritableBehavior + { + Inherit, + Enabled, + Disabled + } +} diff --git a/PlayerTags/InheritableData.cs b/PlayerTags/InheritableData.cs new file mode 100644 index 0000000..eb1e80c --- /dev/null +++ b/PlayerTags/InheritableData.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; + +namespace PlayerTags +{ + [Serializable] + public struct InheritableData + { + [JsonConverter(typeof(StringEnumConverter))] + [JsonProperty("Behavior")] + public InheritableBehavior Behavior; + [JsonProperty("Value")] + [JsonConverter(typeof(GeneralConverter))] + public object Value; + } +} diff --git a/PlayerTags/InheritableReference.cs b/PlayerTags/InheritableReference.cs new file mode 100644 index 0000000..1342500 --- /dev/null +++ b/PlayerTags/InheritableReference.cs @@ -0,0 +1,60 @@ +namespace PlayerTags +{ + public class InheritableReference : IInheritable + where T : class + { + public IInheritable? Parent { get; set; } + + public InheritableBehavior Behavior { get; set; } + + public T Value; + + public T? InheritedValue + { + get + { + IInheritable? current = this; + while (current != null) + { + if (current.Behavior == InheritableBehavior.Enabled && current is InheritableReference currentOfSameType) + { + return currentOfSameType.Value; + } + else if (current.Behavior == InheritableBehavior.Disabled) + { + return default; + } + + current = current.Parent; + } + + return default; + } + } + + public static implicit operator InheritableReference(T value) => new InheritableReference(value) + { + Behavior = InheritableBehavior.Enabled + }; + + public InheritableReference(T value) + { + Value = value; + } + + public void SetData(InheritableData inheritableData) + { + Behavior = inheritableData.Behavior; + Value = (T)inheritableData.Value; + } + + public InheritableData GetData() + { + return new InheritableData + { + Behavior = Behavior, + Value = Value + }; + } + } +} diff --git a/PlayerTags/InheritableValue.cs b/PlayerTags/InheritableValue.cs new file mode 100644 index 0000000..2c80da3 --- /dev/null +++ b/PlayerTags/InheritableValue.cs @@ -0,0 +1,90 @@ +using Dalamud.Logging; +using System; + +namespace PlayerTags +{ + public class InheritableValue : IInheritable + where T : struct + { + public IInheritable? Parent { get; set; } + + public InheritableBehavior Behavior { get; set; } + + public T Value; + + public T? InheritedValue + { + get + { + IInheritable? current = this; + while (current != null) + { + if (current.Behavior == InheritableBehavior.Enabled && current is InheritableValue currentOfSameType) + { + return currentOfSameType.Value; + } + else if (current.Behavior == InheritableBehavior.Disabled) + { + return default; + } + + current = current.Parent; + } + + return default; + } + } + + public static implicit operator InheritableValue(T value) => new InheritableValue(value) + { + Behavior = InheritableBehavior.Enabled + }; + + public InheritableValue(T value) + { + Value = value; + } + + public void SetData(InheritableData inheritableData) + { + Behavior = inheritableData.Behavior; + + try + { + if (typeof(T).IsEnum && inheritableData.Value != null) + { + if (inheritableData.Value is string stringValue) + { + Value = (T)Enum.Parse(typeof(T), stringValue); + } + else + { + Value = (T)Enum.ToObject(typeof(T), inheritableData.Value); + } + } + else if (inheritableData.Value == null) + { + // This should never happen + PluginLog.Error($"Expected value of type {Value.GetType()} but received null"); + } + else + { + Value = (T)Convert.ChangeType(inheritableData.Value, typeof(T)); + } + } + catch (Exception ex) + { + PluginLog.Error(ex, $"Failed to convert {inheritableData.Value.GetType()} value '{inheritableData.Value}' to {Value.GetType()}"); + } + } + + public InheritableData GetData() + { + return new InheritableData + { + Behavior = Behavior, + Value = Value + }; + } + } +} diff --git a/PlayerTags/LiteralPluginString.cs b/PlayerTags/LiteralPluginString.cs new file mode 100644 index 0000000..41ddada --- /dev/null +++ b/PlayerTags/LiteralPluginString.cs @@ -0,0 +1,18 @@ +namespace PlayerTags +{ + public class LiteralPluginString : IPluginString + { + private string m_Value; + public string Value => m_Value; + + public LiteralPluginString(string value) + { + m_Value = value; + } + + public override string ToString() + { + return Value; + } + } +} diff --git a/PlayerTags/LocalizedPluginString.cs b/PlayerTags/LocalizedPluginString.cs new file mode 100644 index 0000000..b45a5cd --- /dev/null +++ b/PlayerTags/LocalizedPluginString.cs @@ -0,0 +1,18 @@ +namespace PlayerTags +{ + public class LocalizedPluginString : IPluginString + { + public string Key { get; init; } + public string Value => Localizer.GetString(Key, false); + + public LocalizedPluginString(string key) + { + Key = key; + } + + public override string ToString() + { + return Value; + } + } +} diff --git a/PlayerTags/Localizer.cs b/PlayerTags/Localizer.cs new file mode 100644 index 0000000..afc110c --- /dev/null +++ b/PlayerTags/Localizer.cs @@ -0,0 +1,50 @@ +using Dalamud.Logging; +using PlayerTags.Resources; +using System; + +namespace PlayerTags +{ + public static class Localizer + { + public static string GetName(TEnum value) + { + return $"{typeof(TEnum).Name}_{value}"; + } + + public static string GetString(bool isDescription) + where TEnum : Enum + { + return GetString(typeof(TEnum).Name, isDescription); + } + + public static string GetString(TEnum value, bool isDescription) + where TEnum : Enum + { + return GetString(GetName(value), isDescription); + } + + public static string GetString(string localizedStringName, bool isDescription) + { + string localizedStringId = $"Loc_{localizedStringName}"; + + if (isDescription) + { + localizedStringId += "_Description"; + } + + return GetString(localizedStringId); + } + + public static string GetString(string localizedStringId) + { + string? value = Strings.ResourceManager.GetString(localizedStringId, Strings.Culture); + if (value != null) + { + return value; + } + + PluginLog.Error($"Failed to get localized string for id {localizedStringId}"); + return localizedStringId; + } + } +} diff --git a/PlayerTags/Config/NameplateElement.cs b/PlayerTags/NameplateElement.cs similarity index 75% rename from PlayerTags/Config/NameplateElement.cs rename to PlayerTags/NameplateElement.cs index c81600a..3636539 100644 --- a/PlayerTags/Config/NameplateElement.cs +++ b/PlayerTags/NameplateElement.cs @@ -1,4 +1,4 @@ -namespace PlayerTags.Config +namespace PlayerTags { public enum NameplateElement { diff --git a/PlayerTags/NameplateFreeCompanyVisibility.cs b/PlayerTags/NameplateFreeCompanyVisibility.cs new file mode 100644 index 0000000..9a37007 --- /dev/null +++ b/PlayerTags/NameplateFreeCompanyVisibility.cs @@ -0,0 +1,8 @@ +namespace PlayerTags +{ + public enum NameplateFreeCompanyVisibility + { + Default, + Never + } +} diff --git a/PlayerTags/Config/TitleNameplatePosition.cs b/PlayerTags/NameplateTitlePosition.cs similarity index 53% rename from PlayerTags/Config/TitleNameplatePosition.cs rename to PlayerTags/NameplateTitlePosition.cs index 92cc6e6..93f30bc 100644 --- a/PlayerTags/Config/TitleNameplatePosition.cs +++ b/PlayerTags/NameplateTitlePosition.cs @@ -1,6 +1,6 @@ -namespace PlayerTags.Config +namespace PlayerTags { - public enum TitleNameplatePosition + public enum NameplateTitlePosition { Default, AlwaysAboveName, diff --git a/PlayerTags/Config/TitleNameplateVisibility.cs b/PlayerTags/NameplateTitleVisibility.cs similarity index 53% rename from PlayerTags/Config/TitleNameplateVisibility.cs rename to PlayerTags/NameplateTitleVisibility.cs index 5d2ee3b..fa3368d 100644 --- a/PlayerTags/Config/TitleNameplateVisibility.cs +++ b/PlayerTags/NameplateTitleVisibility.cs @@ -1,6 +1,6 @@ -namespace PlayerTags.Config +namespace PlayerTags { - public enum TitleNameplateVisibility + public enum NameplateTitleVisibility { Default, Always, diff --git a/PlayerTags/PlayerTags.json b/PlayerTags/PlayerTags.json index c28612d..8817f1e 100644 --- a/PlayerTags/PlayerTags.json +++ b/PlayerTags/PlayerTags.json @@ -3,9 +3,10 @@ "Name": "Player Tags", "Description": "See tags for players in nameplates and chat, such as their role and job, or custom tags for players you know.", "RepoUrl": "https://github.com/r00telement/PlayerTags", - "IconUrl": "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Chat_1.png", + "IconUrl": "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Icon.png", "ImageUrls": [ + "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Nameplates_1.png", "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Chat_1.png", - "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Nameplates_1.png" + "https://github.com/r00telement/PlayerTags/raw/main/PlayerTags/Resources/Promo/Chat_2.png" ] } \ No newline at end of file diff --git a/PlayerTags/Plugin.cs b/PlayerTags/Plugin.cs index dbb89ab..b8bde6c 100644 --- a/PlayerTags/Plugin.cs +++ b/PlayerTags/Plugin.cs @@ -1,5 +1,6 @@ using Dalamud.Data; using Dalamud.Game; +using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.Objects; using Dalamud.Game.ClientState.Objects.Types; using Dalamud.Game.Command; @@ -10,7 +11,6 @@ using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.IoC; using Dalamud.Logging; using Dalamud.Plugin; -using PlayerTags.Config; using System; using System.Collections.Generic; using System.Linq; @@ -44,80 +44,114 @@ namespace PlayerTags [PluginService] private static CommandManager CommandManager { get; set; } = null!; - private MainConfig m_Config; + [PluginService] + private static ClientState ClientState { get; set; } = null!; - private MainConfigUI m_ConfigUI; + private PluginConfiguration m_PluginConfiguration; - private Dictionary m_JobTagPayloads = new Dictionary(); + private PluginConfigurationUI m_PluginConfigurationUI; - private Dictionary m_CustomTagPayloads = new Dictionary(); + private RandomNameGenerator m_RandomNameGenerator = new RandomNameGenerator(); + + private PluginHooks? m_PluginHooks = null; + + private Dictionary> m_TagTargetPayloads = new Dictionary>(); private TextPayload m_SpaceTextPayload = new TextPayload($" "); - private PluginHooks m_PluginHooks; - - private RandomNameGenerator? m_RandomNameGenerator = null; + private PluginData m_PluginData = new PluginData(); public Plugin() { UIColorHelper.Initialize(DataManager); + m_PluginConfiguration = PluginInterface.GetPluginConfig() as PluginConfiguration ?? new PluginConfiguration(); + m_PluginConfiguration.Initialize(PluginInterface); + m_PluginData.Initialize(DataManager, m_PluginConfiguration); + m_PluginConfigurationUI = new PluginConfigurationUI(m_PluginConfiguration, m_PluginData); - m_Config = PluginInterface.GetPluginConfig() as MainConfig ?? new MainConfig(); - m_Config.Initialize(PluginInterface, DataManager); - m_Config.Saved += Configuration_Saved; - - m_ConfigUI = new MainConfigUI(m_Config); - + ClientState.Login += ClientState_Login; + ClientState.Logout += ClientState_Logout; + ClientState.TerritoryChanged += ClientState_TerritoryChanged; + ChatGui.ChatMessage += Chat_ChatMessage; + PluginInterface.UiBuilder.Draw += UiBuilder_Draw; + PluginInterface.UiBuilder.OpenConfigUi += UiBuilder_OpenConfigUi; + m_PluginConfiguration.Saved += PluginConfiguration_Saved; CommandManager.AddHandler(c_CommandName, new CommandInfo((string command, string arguments) => { - m_ConfigUI.IsVisible = true; + m_PluginConfiguration.IsVisible = true; + m_PluginConfiguration.Save(m_PluginData); }) { HelpMessage = "Shows the config" }); - - PluginInterface.UiBuilder.Draw += UiBuilder_Draw; - PluginInterface.UiBuilder.OpenConfigUi += UiBuilder_OpenConfigUi; - - m_PluginHooks = new PluginHooks(Framework, ObjectTable, GameGui, SetNameplate); - - ChatGui.ChatMessage += Chat_ChatMessage; - - if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator == null) - { - m_RandomNameGenerator = new RandomNameGenerator(); - } + Hook(); } public void Dispose() { - PluginInterface.UiBuilder.OpenConfigUi -= UiBuilder_OpenConfigUi; + Unhook(); CommandManager.RemoveHandler(c_CommandName); + m_PluginConfiguration.Saved -= PluginConfiguration_Saved; + PluginInterface.UiBuilder.OpenConfigUi -= UiBuilder_OpenConfigUi; + PluginInterface.UiBuilder.Draw -= UiBuilder_Draw; ChatGui.ChatMessage -= Chat_ChatMessage; - m_Config.Saved -= Configuration_Saved; - m_PluginHooks?.Dispose(); + ClientState.TerritoryChanged -= ClientState_TerritoryChanged; + ClientState.Logout -= ClientState_Logout; + ClientState.Login -= ClientState_Login; } - private void Configuration_Saved() + private void Hook() + { + if (m_PluginHooks == null) + { + m_PluginHooks = new PluginHooks(Framework, ObjectTable, GameGui, SetNameplate); + } + } + + private void Unhook() + { + if (m_PluginHooks != null) + { + m_PluginHooks.Dispose(); + m_PluginHooks = null; + } + } + + private void Rehook() + { + Unhook(); + Hook(); + } + + private void ClientState_Login(object? sender, EventArgs e) + { + Hook(); + } + + private void ClientState_Logout(object? sender, EventArgs e) + { + Unhook(); + } + + private void ClientState_TerritoryChanged(object? sender, ushort e) + { + Rehook(); + } + + private void PluginConfiguration_Saved() { // Invalidate the cached payloads so they get remade - m_JobTagPayloads.Clear(); - m_CustomTagPayloads.Clear(); - - if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator == null) - { - m_RandomNameGenerator = new RandomNameGenerator(); - } + m_TagTargetPayloads.Clear(); } private void UiBuilder_Draw() { - m_ConfigUI.Draw(); + m_PluginConfigurationUI.Draw(); } private void UiBuilder_OpenConfigUi() { - m_ConfigUI.IsVisible = true; + m_PluginConfiguration.IsVisible = true; } private void Chat_ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled) @@ -143,105 +177,101 @@ namespace PlayerTags { AddTagsToNameplate(gameObject, name, title, freeCompany, out isNameChanged, out isTitleChanged, out isFreeCompanyChanged); - if (m_Config.TitlePosition == TitleNameplatePosition.AlwaysAboveName) + if (m_PluginConfiguration.NameplateTitlePosition == NameplateTitlePosition.AlwaysAboveName) { isTitleAboveName = true; } - else if (m_Config.TitlePosition == TitleNameplatePosition.AlwaysBelowName) + else if (m_PluginConfiguration.NameplateTitlePosition == NameplateTitlePosition.AlwaysBelowName) { isTitleAboveName = false; } - if (m_Config.TitleVisibility == TitleNameplateVisibility.Default) + if (m_PluginConfiguration.NameplateTitleVisibility == NameplateTitleVisibility.Default) { } - else if (m_Config.TitleVisibility == TitleNameplateVisibility.Always) + else if (m_PluginConfiguration.NameplateTitleVisibility == NameplateTitleVisibility.Always) { isTitleVisible = true; } - else if (m_Config.TitleVisibility == TitleNameplateVisibility.Never) + else if (m_PluginConfiguration.NameplateTitleVisibility == NameplateTitleVisibility.Never) { isTitleVisible = false; } - else if (m_Config.TitleVisibility == TitleNameplateVisibility.WhenHasTags) + else if (m_PluginConfiguration.NameplateTitleVisibility == NameplateTitleVisibility.WhenHasTags) { isTitleVisible = isTitleChanged; } - if (m_Config.FreeCompanyVisibility == FreeCompanyNameplateVisibility.Default) + if (m_PluginConfiguration.NameplateFreeCompanyVisibility == NameplateFreeCompanyVisibility.Default) { } - else if (m_Config.FreeCompanyVisibility == FreeCompanyNameplateVisibility.Never) + else if (m_PluginConfiguration.NameplateFreeCompanyVisibility == NameplateFreeCompanyVisibility.Never) { freeCompany.Payloads.Clear(); isFreeCompanyChanged = true; } } - /// - /// Gets the job tag payloads for the given character. If the payloads don't yet exist then they are created. - /// - /// The character to get job tag payloads for. - /// A list of job tag payloads for the given character. - private IEnumerable GetJobTagPayloads(Character character) + private Payload[] CreateTagPayloads(TagTarget tagTarget, Tag tag) { - var roleId = character.ClassJob.GameData.Role; - var jobAbbreviation = character.ClassJob.GameData.Abbreviation; - var role = MainConfig.RolesById[roleId]; - - var roleConfig = m_Config.RoleTag.RoleOverrideConfigs[role]; - if (!roleConfig.IsEnabled) - { - return new Payload[] { }; - } - - if (m_JobTagPayloads.TryGetValue(jobAbbreviation, out var payloads)) - { - return payloads; - } - - string text = ""; - if (m_Config.RoleTag.Format == RoleTagFormat.AbbreviatedJobName) - { - text = character.ClassJob.GameData.Abbreviation; - } - else if (m_Config.RoleTag.Format == RoleTagFormat.JobName) - { - text = character.ClassJob.GameData.NameEnglish; - } - else if (m_Config.RoleTag.Format == RoleTagFormat.RoleName) - { - text = m_Config.RoleTag.RoleOverrideConfigs[role].Name; - } - List newPayloads = new List(); - // There will always be a text payload - newPayloads.Add(new TextPayload(text)); - - ushort? colorId = null; - - // Pick a color id if one is available - if (roleConfig.JobOverrideConfigs[jobAbbreviation].CustomColor.Id != null) + BitmapFontIcon? icon = null; + if (tagTarget == TagTarget.Chat && tag.IsIconVisibleInChat.InheritedValue != null && tag.IsIconVisibleInChat.InheritedValue.Value) { - colorId = roleConfig.JobOverrideConfigs[jobAbbreviation].CustomColor.Id!.Value; + icon = tag.Icon.InheritedValue; } - else if (roleConfig.CustomColor.Id != null) + else if (tagTarget == TagTarget.Nameplate && tag.IsIconVisibleInNameplates.InheritedValue != null && tag.IsIconVisibleInNameplates.InheritedValue.Value) { - colorId = roleConfig.CustomColor.Id.Value; + icon = tag.Icon.InheritedValue; } - // If we picked a color id, add the payloads for it - if (colorId != null) + string? text = null; + if (tagTarget == TagTarget.Chat && tag.IsTextVisibleInChat.InheritedValue != null && tag.IsTextVisibleInChat.InheritedValue.Value) { - newPayloads.Insert(0, new UIForegroundPayload(colorId.Value)); - newPayloads.Add(new UIForegroundPayload(0)); + text = tag.Text.InheritedValue; + } + else if (tagTarget == TagTarget.Nameplate && tag.IsTextVisibleInNameplates.InheritedValue != null && tag.IsTextVisibleInNameplates.InheritedValue.Value) + { + text = tag.Text.InheritedValue; } - var newPayloadsArray = newPayloads.ToArray(); - m_JobTagPayloads[jobAbbreviation] = newPayloadsArray; + if (!m_TagTargetPayloads.ContainsKey(tag)) + { + m_TagTargetPayloads[tag] = new Dictionary(); + } - return newPayloadsArray; + if (icon != null && icon.Value != BitmapFontIcon.None) + { + newPayloads.Add(new IconPayload(icon.Value)); + } + + if (!string.IsNullOrWhiteSpace(text)) + { + if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value) + { + newPayloads.Add(new EmphasisItalicPayload(true)); + } + + if (tag.TextColor.InheritedValue != null) + { + newPayloads.Add(new UIForegroundPayload(tag.TextColor.InheritedValue.Value)); + } + + newPayloads.Add(new TextPayload(text)); + + if (tag.IsTextItalic.InheritedValue != null && tag.IsTextItalic.InheritedValue.Value) + { + newPayloads.Add(new EmphasisItalicPayload(false)); + } + + if (tag.TextColor.InheritedValue != null) + { + newPayloads.Add(new UIForegroundPayload(0)); + } + } + + return newPayloads.ToArray(); } /// @@ -249,51 +279,83 @@ namespace PlayerTags /// /// The custom tag config to get payloads for. /// A list of payloads for the given custom tag. - private IEnumerable GetCustomTagPayloads(CustomTagConfig customTagConfig) + private IEnumerable GetTagPayloads(TagTarget tagTarget, Tag tag) { - if (m_CustomTagPayloads.TryGetValue(customTagConfig, out var payloads)) + if (m_TagTargetPayloads.TryGetValue(tag, out var tagTargetPayloads)) { - return payloads; + if (tagTargetPayloads.TryGetValue(tagTarget, out var payloads)) + { + return payloads; + } + } + else + { + m_TagTargetPayloads[tag] = new Dictionary(); } - List newPayloads = new List(); - - // There will always be a text payload - newPayloads.Add(new TextPayload(customTagConfig.Name)); - - ushort? colorId = null; - - // Pick a color id if one is available - if (customTagConfig.CustomColor.Id != null) - { - colorId = customTagConfig.CustomColor.Id!.Value; - } - - // If we picked a color id, add the payloads for it - if (colorId != null) - { - newPayloads.Insert(0, new UIForegroundPayload(colorId.Value)); - newPayloads.Add(new UIForegroundPayload(0)); - } - - var newPayloadsArray = newPayloads.ToArray(); - m_CustomTagPayloads[customTagConfig] = newPayloadsArray; - - return newPayloadsArray; + m_TagTargetPayloads[tag][tagTarget] = CreateTagPayloads(tagTarget, tag); + return m_TagTargetPayloads[tag][tagTarget]; } - /// - /// Adds an additional space text payload in between any existing text payloads. + /// Adds an additional space text payload in between any existing text payloads. If there is an icon payload between two text payloads then the space is skipped. + /// Also adds an extra space to the beginning or end depending on the tag position and whether the most significant payload in either direction is a text payload. + /// In spirit, this is to ensure there is always a space between 2 text payloads, including between these payloads and the target payload. /// /// The payloads to add spaces between. - private void AddSpacesBetweenTextPayloads(List payloads) + private void AddSpacesBetweenTextPayloads(List payloads, TagPosition tagPosition) { - var textPayloads = payloads.Where(payload => payload is TextPayload).ToList(); - foreach (var textPayload in textPayloads.Skip(1)) + if (payloads == null) { - var index = payloads.IndexOf(textPayload); - payloads.Insert(index, m_SpaceTextPayload); + return; + } + + if (!payloads.Any()) + { + return; + } + + List indicesToInsertSpacesAt = new List(); + int lastTextPayloadIndex = -1; + foreach (var payload in payloads.Reverse()) + { + if (payload is IconPayload iconPayload) + { + lastTextPayloadIndex = -1; + } + else if (payload is TextPayload textPayload) + { + if (lastTextPayloadIndex != -1) + { + indicesToInsertSpacesAt.Add(payloads.IndexOf(textPayload) + 1); + } + + lastTextPayloadIndex = payloads.IndexOf(textPayload); + } + } + + foreach (var indexToInsertSpaceAt in indicesToInsertSpacesAt) + { + payloads.Insert(indexToInsertSpaceAt, m_SpaceTextPayload); + } + + // Decide whether to add a space to the end + if (tagPosition == TagPosition.Before) + { + var significantPayloads = payloads.Where(payload => payload is TextPayload || payload is IconPayload); + if (significantPayloads.Last() is TextPayload) + { + payloads.Add(m_SpaceTextPayload); + } + } + // Decide whether to add a space to the beginning + else if (tagPosition == TagPosition.After) + { + var significantPayloads = payloads.Where(payload => payload is TextPayload || payload is IconPayload); + if (significantPayloads.First() is TextPayload) + { + payloads.Insert(0, m_SpaceTextPayload); + } } } @@ -313,15 +375,19 @@ namespace PlayerTags public TextPayload TextPayload { get; init; } /// - /// The matching game object. + /// The matching game object if one exists /// public GameObject? GameObject { get; init; } - public StringMatch(SeString seString, TextPayload textPayload, GameObject? gameObject = null) + /// + /// A matching player payload if one exists. + /// + public PlayerPayload? PlayerPayload { get; init; } + + public StringMatch(SeString seString, TextPayload textPayload) { SeString = seString; TextPayload = textPayload; - GameObject = gameObject; } /// @@ -358,7 +424,11 @@ namespace PlayerTags // The next payload MUST be a text payload if (payloadIndex + 1 < seString.Payloads.Count && seString.Payloads[payloadIndex + 1] is TextPayload textPayload) { - var stringMatch = new StringMatch(seString, textPayload, gameObject); + var stringMatch = new StringMatch(seString, textPayload) + { + GameObject = gameObject, + PlayerPayload = playerPayload + }; stringMatches.Add(stringMatch); // Don't handle the text payload twice @@ -370,18 +440,25 @@ namespace PlayerTags } } + /// TODO: Not sure if this is desirable. Enabling this allows tags to appear next to the name of the local player by text in chat because the local player doesn't have a player payload. + /// But because it's just a simple string comparison, it won't work in all circumstances. E.g. in party chat the player name is wrapped in (). To be comprehensive we need to search substring. + /// This means we would need to think about breaking down existing payloads to split them out. + /// If we decide to do that, we could even for example find unlinked player names in chat and add player payloads for them. // If it's just a text payload then either a character NEEDS to exist for it, or it needs to be identified as a character by custom tag configs - else if (payload is TextPayload textPayload) - { - var gameObject = ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == textPayload.Text); - var isIncludedInCustomTagConfig = m_Config.CustomTagConfigs.Any(customTagConfig => customTagConfig.IncludesGameObjectName(textPayload.Text)); + //else if (payload is TextPayload textPayload) + //{ + // var gameObject = ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == textPayload.Text); + // var isIncludedInCustomTagConfig = m_Config.CustomTags.Any(customTagConfig => customTagConfig.IncludesGameObjectName(textPayload.Text)); - if (gameObject != null || isIncludedInCustomTagConfig) - { - var stringMatch = new StringMatch(seString, textPayload, gameObject); - stringMatches.Add(stringMatch); - } - } + // if (gameObject != null || isIncludedInCustomTagConfig) + // { + // var stringMatch = new StringMatch(seString, textPayload) + // { + // GameObject = gameObject + // }; + // stringMatches.Add(stringMatch); + // } + //} } return stringMatches; @@ -390,32 +467,37 @@ namespace PlayerTags /// /// Adds the given payload changes to the dictionary. /// - /// The position of the string to add changes to. + /// The position to add changes to. /// The payloads to add. /// The dictionary to add the changes to. - private void AddPayloadChanges(StringPosition stringPosition, IEnumerable payloads, Dictionary> stringChanges) + private void AddPayloadChanges(TagPosition tagPosition, IEnumerable payloads, Dictionary> stringChanges) { - if (!payloads.Any()) + if (payloads == null || !payloads.Any()) { return; } - if (!stringChanges.Keys.Contains(stringPosition)) + if (stringChanges == null) { - stringChanges[stringPosition] = new List(); + return; } - stringChanges[stringPosition].AddRange(payloads); + if (!stringChanges.Keys.Contains(tagPosition)) + { + stringChanges[tagPosition] = new List(); + } + + stringChanges[tagPosition].AddRange(payloads); } /// /// Adds the given payload changes to the dictionary. /// /// The nameplate element to add changes to. - /// The position of the string to add changes to. + /// The position to add changes to. /// The payloads to add. /// The dictionary to add the changes to. - private void AddPayloadChanges(NameplateElement nameplateElement, StringPosition stringPosition, IEnumerable payloads, Dictionary>> nameplateChanges) + private void AddPayloadChanges(NameplateElement nameplateElement, TagPosition tagPosition, IEnumerable payloads, Dictionary>> nameplateChanges) { if (!payloads.Any()) { @@ -424,10 +506,10 @@ namespace PlayerTags if (!nameplateChanges.Keys.Contains(nameplateElement)) { - nameplateChanges[nameplateElement] = new Dictionary>(); + nameplateChanges[nameplateElement] = new Dictionary>(); } - AddPayloadChanges(stringPosition, payloads, nameplateChanges[nameplateElement]); + AddPayloadChanges(tagPosition, payloads, nameplateChanges[nameplateElement]); } /// @@ -436,53 +518,71 @@ namespace PlayerTags /// The string to apply changes to. /// The changes to apply. /// The payload in the string that changes should be anchored to. If there is no anchor, the changes will be applied to the entire string. - private void ApplyStringChanges(SeString seString, Dictionary> stringChanges, Payload? anchorPayload = null) + private void ApplyStringChanges(SeString seString, Dictionary> stringChanges, Payload? anchorPayload = null) { - foreach ((var stringPosition, var payloads) in stringChanges) + if (stringChanges.Count == 0) { - if (!payloads.Any()) - { - continue; - } + return; + } - AddSpacesBetweenTextPayloads(payloads); + List tagPositionsOrdered = new List(); + // If there's no anchor payload, do replaces first so that befores and afters are based on the replaced data + if (anchorPayload == null) + { + tagPositionsOrdered.Add(TagPosition.Replace); + } - if (stringPosition == StringPosition.Before) + tagPositionsOrdered.Add(TagPosition.Before); + tagPositionsOrdered.Add(TagPosition.After); + + // If there is an anchor payload, do replaces last so that we still know which payload needs to be removed + if (anchorPayload != null) + { + tagPositionsOrdered.Add(TagPosition.Replace); + } + + foreach (var tagPosition in tagPositionsOrdered) + { + if (stringChanges.TryGetValue(tagPosition, out var payloads) && payloads.Any()) { - if (anchorPayload != null) + AddSpacesBetweenTextPayloads(stringChanges[tagPosition], tagPosition); + if (tagPosition == TagPosition.Before) { - var payloadIndex = seString.Payloads.IndexOf(anchorPayload); - seString.Payloads.InsertRange(payloadIndex, payloads.Append(m_SpaceTextPayload)); + if (anchorPayload != null) + { + var anchorPayloadIndex = seString.Payloads.IndexOf(anchorPayload); + seString.Payloads.InsertRange(anchorPayloadIndex, payloads); + } + else + { + seString.Payloads.InsertRange(0, payloads); + } } - else + else if (tagPosition == TagPosition.After) { - seString.Payloads.InsertRange(0, payloads.Append(m_SpaceTextPayload)); + if (anchorPayload != null) + { + var anchorPayloadIndex = seString.Payloads.IndexOf(anchorPayload); + seString.Payloads.InsertRange(anchorPayloadIndex + 1, payloads); + } + else + { + seString.Payloads.AddRange(payloads); + } } - } - else if (stringPosition == StringPosition.After) - { - if (anchorPayload != null) + else if (tagPosition == TagPosition.Replace) { - var payloadIndex = seString.Payloads.IndexOf(anchorPayload); - seString.Payloads.InsertRange(payloadIndex + 1, payloads.Prepend(m_SpaceTextPayload)); - } - else - { - seString.Payloads.AddRange(payloads.Prepend(m_SpaceTextPayload)); - } - } - else if (stringPosition == StringPosition.Replace) - { - if (anchorPayload != null) - { - var payloadIndex = seString.Payloads.IndexOf(anchorPayload); - seString.Payloads.InsertRange(payloadIndex, payloads); - seString.Payloads.Remove(anchorPayload); - } - else - { - seString.Payloads.Clear(); - seString.Payloads.AddRange(payloads); + if (anchorPayload != null) + { + var anchorPayloadIndex = seString.Payloads.IndexOf(anchorPayload); + seString.Payloads.InsertRange(anchorPayloadIndex, payloads); + seString.Payloads.Remove(anchorPayload); + } + else + { + seString.Payloads.Clear(); + seString.Payloads.AddRange(payloads); + } } } } @@ -504,18 +604,25 @@ namespace PlayerTags isTitleChanged = false; isFreeCompanyChanged = false; - Dictionary>> nameplateChanges = new Dictionary>>(); + Dictionary>> nameplateChanges = new Dictionary>>(); if (gameObject is Character character) { - // Add the role tag payloads - if (m_Config.RoleTag.NameplatePosition != StringPosition.None) + // Add the job tag + if (m_PluginData.JobTags.TryGetValue(character.ClassJob.GameData.Abbreviation, out var jobTag)) { - AddPayloadChanges(m_Config.RoleTag.NameplateElement, m_Config.RoleTag.NameplatePosition, GetJobTagPayloads(character), nameplateChanges); + if (jobTag.TagTargetInNameplates.InheritedValue != null && jobTag.TagPositionInNameplates.InheritedValue != null) + { + var payloads = GetTagPayloads(TagTarget.Nameplate, jobTag); + if (payloads.Any()) + { + AddPayloadChanges(jobTag.TagTargetInNameplates.InheritedValue.Value, jobTag.TagPositionInNameplates.InheritedValue.Value, payloads, nameplateChanges); + } + } } - // Add randomly generated name tag payload - if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator != null) + // Add the randomly generated name tag payload + if (m_PluginConfiguration.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator != null) { var characterName = character.Name.TextValue; if (characterName != null) @@ -523,18 +630,25 @@ namespace PlayerTags var generatedName = m_RandomNameGenerator.GetGeneratedName(characterName); if (generatedName != null) { - AddPayloadChanges(NameplateElement.Name, StringPosition.Replace, Enumerable.Empty().Append(new TextPayload(generatedName)), nameplateChanges); + AddPayloadChanges(NameplateElement.Name, TagPosition.Replace, Enumerable.Empty().Append(new TextPayload(generatedName)), nameplateChanges); } } } } // Add the custom tag payloads - foreach (var customTagConfig in m_Config.CustomTagConfigs) + foreach (var customTag in m_PluginData.CustomTags) { - if (customTagConfig.NameplatePosition != StringPosition.None && customTagConfig.FormattedGameObjectNames.Split(',').Contains(gameObject.Name.TextValue)) + if (customTag.TagTargetInNameplates.InheritedValue != null && customTag.TagPositionInNameplates.InheritedValue != null) { - AddPayloadChanges(customTagConfig.NameplateElement, customTagConfig.NameplatePosition, GetCustomTagPayloads(customTagConfig), nameplateChanges); + if (customTag.IncludesGameObjectNameToApplyTo(gameObject.Name.TextValue)) + { + var payloads = GetTagPayloads(TagTarget.Nameplate, customTag); + if (payloads.Any()) + { + AddPayloadChanges(customTag.TagTargetInNameplates.InheritedValue.Value, customTag.TagPositionInNameplates.InheritedValue.Value, payloads, nameplateChanges); + } + } } } @@ -577,37 +691,52 @@ namespace PlayerTags var stringMatches = GetStringMatches(message); foreach (var stringMatch in stringMatches) { - Dictionary> stringChanges = new Dictionary>(); + Dictionary> stringChanges = new Dictionary>(); // The role tag payloads if (stringMatch.GameObject is Character character) { - if (m_Config.RoleTag.ChatPosition != StringPosition.None) + // Add the job tag + if (m_PluginData.JobTags.TryGetValue(character.ClassJob.GameData.Abbreviation, out var jobTag)) { - AddPayloadChanges(m_Config.RoleTag.ChatPosition, GetJobTagPayloads(character), stringChanges); - } - } - - // Add randomly generated name tag payload - if (m_Config.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator != null) - { - var playerName = stringMatch.GetMatchText(); - if (playerName != null) - { - var generatedName = m_RandomNameGenerator.GetGeneratedName(playerName); - if (generatedName != null) + if (jobTag.TagPositionInChat.InheritedValue != null) { - AddPayloadChanges(StringPosition.Replace, Enumerable.Empty().Append(new TextPayload(generatedName)), stringChanges); + var payloads = GetTagPayloads(TagTarget.Chat, jobTag); + if (payloads.Any()) + { + AddPayloadChanges(jobTag.TagPositionInChat.InheritedValue.Value, payloads, stringChanges); + } + } + } + + // Add randomly generated name tag payload + if (m_PluginConfiguration.IsPlayerNameRandomlyGenerated && m_RandomNameGenerator != null) + { + var playerName = stringMatch.GetMatchText(); + if (playerName != null) + { + var generatedName = m_RandomNameGenerator.GetGeneratedName(playerName); + if (generatedName != null) + { + AddPayloadChanges(TagPosition.Replace, Enumerable.Empty().Append(new TextPayload(generatedName)), stringChanges); + } } } } // Add the custom tag payloads - foreach (var customTagConfig in m_Config.CustomTagConfigs) + foreach (var customTag in m_PluginData.CustomTags) { - if (customTagConfig.IncludesGameObjectName(stringMatch.GetMatchText())) + if (customTag.TagPositionInChat.InheritedValue != null) { - AddPayloadChanges(customTagConfig.ChatPosition, GetCustomTagPayloads(customTagConfig), stringChanges); + if (customTag.IncludesGameObjectNameToApplyTo(stringMatch.GetMatchText())) + { + var customTagPayloads = GetTagPayloads(TagTarget.Chat, customTag); + if (customTagPayloads.Any()) + { + AddPayloadChanges(customTag.TagPositionInChat.InheritedValue.Value, customTagPayloads, stringChanges); + } + } } } diff --git a/PlayerTags/PluginConfiguration.cs b/PlayerTags/PluginConfiguration.cs new file mode 100644 index 0000000..c315bf9 --- /dev/null +++ b/PlayerTags/PluginConfiguration.cs @@ -0,0 +1,94 @@ +using Dalamud.Configuration; +using Dalamud.Plugin; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PlayerTags +{ + [Serializable] + public class PluginConfiguration : IPluginConfiguration + { + public int Version { get; set; } = 0; + public bool IsVisible = false; + public NameplateFreeCompanyVisibility NameplateFreeCompanyVisibility = NameplateFreeCompanyVisibility.Default; + public NameplateTitleVisibility NameplateTitleVisibility = NameplateTitleVisibility.WhenHasTags; + public NameplateTitlePosition NameplateTitlePosition = NameplateTitlePosition.AlwaysAboveName; + public bool IsPlayerNameRandomlyGenerated = false; + + [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] + public Dictionary AllTagsChanges = new Dictionary(); + + [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] + public Dictionary AllRoleTagsChanges = new Dictionary(); + + [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] + public Dictionary> RoleTagsChanges = new Dictionary>(); + + [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] + public Dictionary> JobTagsChanges = new Dictionary>(); + + [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] + public Dictionary AllCustomTagsChanges = new Dictionary(); + + [JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)] + public List> CustomTagsChanges = new List>(); + + [NonSerialized] + private DalamudPluginInterface? m_PluginInterface; + + public event System.Action? Saved; + + public void Initialize(DalamudPluginInterface pluginInterface) + { + m_PluginInterface = pluginInterface; + } + + public void Save(PluginData pluginData) + { + AllTagsChanges = pluginData.AllTags.GetChanges(pluginData.Default.AllTagsChanges); + AllRoleTagsChanges = pluginData.AllRoleTags.GetChanges(pluginData.Default.AllRoleTagsChanges); + + RoleTagsChanges = new Dictionary>(); + foreach ((var role, var roleTag) in pluginData.RoleTags) + { + Dictionary? defaultChanges; + pluginData.Default.RoleTagsChanges.TryGetValue(role, out defaultChanges); + + var changes = roleTag.GetChanges(defaultChanges); + if (changes.Any()) + { + RoleTagsChanges[role] = changes; + } + } + + JobTagsChanges = new Dictionary>(); + foreach ((var jobAbbreviation, var jobTag) in pluginData.JobTags) + { + Dictionary? defaultChanges; + pluginData.Default.JobTagsChanges.TryGetValue(jobAbbreviation, out defaultChanges); + + var changes = jobTag.GetChanges(defaultChanges); + if (changes.Any()) + { + JobTagsChanges[jobAbbreviation] = changes; + } + } + + AllCustomTagsChanges = pluginData.AllCustomTags.GetChanges(pluginData.Default.AllCustomTagsChanges); + + CustomTagsChanges = new List>(); + foreach (var customTag in pluginData.CustomTags) + { + CustomTagsChanges.Add(customTag.GetChanges()); + } + + if (m_PluginInterface != null) + { + m_PluginInterface.SavePluginConfig(this); + Saved?.Invoke(); + }; + } + } +} diff --git a/PlayerTags/PluginConfigurationUI.cs b/PlayerTags/PluginConfigurationUI.cs new file mode 100644 index 0000000..3e524b5 --- /dev/null +++ b/PlayerTags/PluginConfigurationUI.cs @@ -0,0 +1,571 @@ +using ImGuiNET; +using Lumina.Excel.GeneratedSheets; +using PlayerTags.Resources; +using System; +using System.Linq; +using System.Numerics; + +namespace PlayerTags +{ + public class PluginConfigurationUI + { + private PluginConfiguration m_PluginConfiguration; + + private PluginData m_PluginData; + + private InheritableValue? m_ColorPickerPopupDataContext; + + public PluginConfigurationUI(PluginConfiguration config, PluginData pluginData) + { + m_PluginConfiguration = config; + m_PluginData = pluginData; + } + + public void Draw() + { + if (m_PluginConfiguration == null || !m_PluginConfiguration.IsVisible) + { + return; + } + + if (ImGui.Begin(Strings.Loc_Static_PluginName, ref m_PluginConfiguration.IsVisible)) + { + ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1, 0.8f, 0.5f, 1)); + ImGui.TextWrapped(Strings.Loc_Static_WarningMessage); + ImGui.PopStyleColor(); + + DrawHeading(Strings.Loc_Static_Nameplates); + ImGui.TreePush(); + DrawComboBox(true, true, false, ref m_PluginConfiguration.NameplateFreeCompanyVisibility, () => m_PluginConfiguration.Save(m_PluginData)); + DrawComboBox(true, true, false, ref m_PluginConfiguration.NameplateTitleVisibility, () => m_PluginConfiguration.Save(m_PluginData)); + DrawComboBox(true, true, false, ref m_PluginConfiguration.NameplateTitlePosition, () => m_PluginConfiguration.Save(m_PluginData)); + ImGui.TreePop(); + + DrawHeading(Strings.Loc_Static_Development); + ImGui.TreePush(); + DrawCheckbox(nameof(m_PluginConfiguration.IsPlayerNameRandomlyGenerated), true, ref m_PluginConfiguration.IsPlayerNameRandomlyGenerated, () => m_PluginConfiguration.Save(m_PluginData)); + ImGui.TreePop(); + ImGui.EndTabItem(); + + DrawHeading(Strings.Loc_Static_Tags); + ImGui.TreePush(); + int depth = 0; + Draw(m_PluginData.AllTags, ref depth); + + if (ImGui.Button(Strings.Loc_Static_AddCustomTag)) + { + var newTag = new Tag(new LocalizedPluginString(nameof(PluginData.CustomTags))) + { + Text = "", + GameObjectNamesToApplyTo = "" + }; + + m_PluginData.CustomTags.Add(newTag); + newTag.Parent = m_PluginData.AllCustomTags; + } + ImGui.TreePop(); + ImGui.End(); + } + + if (!m_PluginConfiguration.IsVisible) + { + m_PluginConfiguration.Save(m_PluginData); + } + } + + public void Draw(Tag tag, ref int depth) + { + ImGui.PushID(tag.GetHashCode().ToString()); + + ImGui.BeginGroup(); + ImGui.BeginChild(tag.GetHashCode().ToString(), new Vector2(100, 60)); + + var text = tag.Name.Value; + var textSize = ImGui.CalcTextSize(text); + var addButtonSize = new Vector2(23, 23); + var panelSize = ImGui.GetItemRectSize(); + + ImGui.SetCursorPosX(panelSize.X - textSize.X); + ImGui.Text(text); + + if (ImGui.IsPopupOpen("AddPopup")) + { + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.2f, 0.6f, 0.2f, 1)); + } + else + { + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.1f, 0.3f, 0.1f, 1)); + } + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.2f, 0.6f, 0.2f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.2f, 0.6f, 0.2f, 1)); + ImGui.SetCursorPosX(panelSize.X - addButtonSize.X); + var addPopupPos = ImGui.GetCursorPos(); + addPopupPos.Y -= addButtonSize.Y + 2; + if (ImGui.Button("+", addButtonSize)) + { + ImGui.OpenPopup("AddPopup"); + } + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + + bool wasPaddingConsumed = false; + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 5)); + ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos() + addPopupPos); + if (ImGui.BeginPopup("AddPopup")) + { + wasPaddingConsumed = true; + ImGui.PopStyleVar(); + + ImGui.PushStyleColor(ImGuiCol.FrameBg, new Vector4(0f, 0f, 0f, 0)); + if (ImGui.BeginListBox("###SelectableInheritables")) + { + var selectableInheritables = tag.Inheritables.Where(inheritable => inheritable.Value.Behavior == InheritableBehavior.Inherit).ToDictionary(item => item.Key, item => item.Value); + var selectableInheritablesWithLocalizedNames = selectableInheritables + .Select(inheritable => new { Name = inheritable.Key, LocalizedName = Localizer.GetString(inheritable.Key, false) }) + .OrderBy(item => item.LocalizedName); + + foreach (var inheritableLocalizedName in selectableInheritablesWithLocalizedNames) + { + bool isSelected = false; + if (ImGui.Selectable(inheritableLocalizedName.LocalizedName, isSelected)) + { + selectableInheritables[inheritableLocalizedName.Name].Behavior = InheritableBehavior.Enabled; + + if (selectableInheritables[inheritableLocalizedName.Name] is InheritableValue inheritableBool) + { + inheritableBool.Value = true; + } + + m_PluginConfiguration.Save(m_PluginData); + ImGui.CloseCurrentPopup(); + } + + if (isSelected) + { + ImGui.SetItemDefaultFocus(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Localizer.GetString(inheritableLocalizedName.Name, true)); + } + } + + ImGui.EndListBox(); + } + ImGui.PopStyleColor(); + ImGui.EndPopup(); + } + if (!wasPaddingConsumed) + { + ImGui.PopStyleVar(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Strings.Loc_Static_AddPropertyOverride_Description); + } + ImGui.EndChild(); + ImGui.EndGroup(); + + ImGui.SameLine(); + ImGui.BeginGroup(); + + var selectedInheritables = tag.Inheritables.Where(inheritable => inheritable.Value.Behavior != InheritableBehavior.Inherit).ToDictionary(item => item.Key, item => item.Value); + var selectedInheritablesWithLocalizedNames = selectedInheritables + .Select(inheritable => new { Name = inheritable.Key, LocalizedName = Localizer.GetString(inheritable.Key, false) }) + .OrderBy(item => item.LocalizedName); + + foreach (var selectedInheritablesWithLocalizedName in selectedInheritablesWithLocalizedNames) + { + switch (selectedInheritablesWithLocalizedName.Name) + { + case nameof(tag.Icon): + ImGui.SameLine(); + DrawInheritable(nameof(tag.Icon), false, true, tag.Icon); + break; + case nameof(tag.IsIconVisibleInChat): + ImGui.SameLine(); + DrawInheritable(nameof(tag.IsIconVisibleInChat), tag.IsIconVisibleInChat); + break; + case nameof(tag.IsIconVisibleInNameplates): + ImGui.SameLine(); + DrawInheritable(nameof(tag.IsIconVisibleInNameplates), tag.IsIconVisibleInNameplates); + break; + case nameof(tag.Text): + ImGui.SameLine(); + DrawInheritable(nameof(tag.Text), tag.Text); + break; + case nameof(tag.TextColor): + ImGui.SameLine(); + DrawInheritable(nameof(tag.TextColor), tag.TextColor); + break; + case nameof(tag.IsTextItalic): + ImGui.SameLine(); + DrawInheritable(nameof(tag.IsTextItalic), tag.IsTextItalic); + break; + case nameof(tag.IsTextVisibleInChat): + ImGui.SameLine(); + DrawInheritable(nameof(tag.IsTextVisibleInChat), tag.IsTextVisibleInChat); + break; + case nameof(tag.IsTextVisibleInNameplates): + ImGui.SameLine(); + DrawInheritable(nameof(tag.IsTextVisibleInNameplates), tag.IsTextVisibleInNameplates); + break; + case nameof(tag.TagPositionInChat): + ImGui.SameLine(); + DrawInheritable(nameof(tag.TagPositionInChat), true, false, tag.TagPositionInChat); + break; + case nameof(tag.TagPositionInNameplates): + ImGui.SameLine(); + DrawInheritable(nameof(tag.TagPositionInNameplates), true, false, tag.TagPositionInNameplates); + break; + case nameof(tag.TagTargetInNameplates): + ImGui.SameLine(); + DrawInheritable(nameof(tag.TagTargetInNameplates), true, false, tag.TagTargetInNameplates); + break; + case nameof(tag.GameObjectNamesToApplyTo): + ImGui.SameLine(); + DrawInheritable(nameof(tag.GameObjectNamesToApplyTo), tag.GameObjectNamesToApplyTo); + break; + default: + break; + } + } + + if (m_PluginData.CustomTags.Contains(tag)) + { + ImGui.SameLine(); + ImGui.BeginGroup(); + ImGui.Indent(); + if (ImGui.Button(Strings.Loc_Static_RemoveCustomTag)) + { + m_PluginData.AllCustomTags.Children.Remove(tag); + m_PluginData.CustomTags.Remove(tag); + m_PluginConfiguration.Save(m_PluginData); + } + ImGui.EndGroup(); + } + ImGui.EndGroup(); + + foreach (var childTag in tag.Children.ToArray()) + { + depth++; + Draw(childTag, ref depth); + } + depth++; + + ImGui.PopID(); + } + + private void DrawRemoveButton(IInheritable inheritable) + { + + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(0, 0)); + ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(0.3f, 0.1f, 0.1f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(0.6f, 0.2f, 0.2f, 1)); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(0.6f, 0.2f, 0.2f, 1)); + + if (ImGui.Button($"x", new Vector2(23, 23))) + { + inheritable.Behavior = InheritableBehavior.Inherit; + m_PluginConfiguration.Save(m_PluginData); + } + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.PopStyleVar(); + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Strings.Loc_Static_RemovePropertyOverride_Description); + } + } + + private void DrawInheritable(string localizedStringName, InheritableValue inheritable) + { + ImGui.BeginGroup(); + ImGui.Indent(); + ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); + + ImGui.Text(Localizer.GetString(localizedStringName, false)); + DrawCheckbox("IsEnabled", false, ref inheritable.Value, () => + { + m_PluginConfiguration.Save(m_PluginData); + }); + ImGui.SameLine(); + DrawRemoveButton(inheritable); + + ImGui.EndChild(); + ImGui.EndGroup(); + } + + private void DrawInheritable(string localizedStringName, bool shouldLocalizeNames, bool shouldOrderNames, InheritableValue inheritable) + where TEnum : struct, Enum + { + ImGui.BeginGroup(); + ImGui.Indent(); + ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); + + ImGui.Text(Localizer.GetString(localizedStringName, false)); + + bool isEnabled = inheritable.Behavior == InheritableBehavior.Enabled; + DrawCheckbox("IsEnabled", false, ref isEnabled, () => + { + if (isEnabled) + { + inheritable.Behavior = InheritableBehavior.Enabled; + } + else + { + inheritable.Behavior = InheritableBehavior.Disabled; + } + m_PluginConfiguration.Save(m_PluginData); + }); + + if (isEnabled) + { + ImGui.SameLine(); + DrawComboBox(false, shouldLocalizeNames, shouldOrderNames, ref inheritable.Value, () => { m_PluginConfiguration.Save(m_PluginData); }); + } + + ImGui.SameLine(); + DrawRemoveButton(inheritable); + + ImGui.EndChild(); + ImGui.EndGroup(); + } + + private void DrawInheritable(string localizedStringName, InheritableValue inheritable) + { + ImGui.BeginGroup(); + ImGui.Indent(); + ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); + + ImGui.Text(Localizer.GetString(localizedStringName, false)); + + bool isEnabled = inheritable.Behavior == InheritableBehavior.Enabled; + DrawCheckbox("IsEnabled", false, ref isEnabled, () => + { + if (isEnabled) + { + inheritable.Behavior = InheritableBehavior.Enabled; + } + else + { + inheritable.Behavior = InheritableBehavior.Disabled; + } + m_PluginConfiguration.Save(m_PluginData); + }); + + if (isEnabled) + { + ImGui.SameLine(); + DrawColorButton( + inheritable.Value.ToString(), + UIColorHelper.ToColor(inheritable.Value), + () => + { + m_ColorPickerPopupDataContext = inheritable; + ImGui.OpenPopup("ColorPickerPopup"); + }); + } + + bool wasStyleConsumed = false; + ImGui.SetNextWindowPos(ImGui.GetCursorScreenPos() + new Vector2(31, 0)); + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0)); + if (ImGui.BeginPopup("ColorPickerPopup")) + { + wasStyleConsumed = true; + ImGui.PopStyleVar(); + + DrawUIColorPicker( + (UIColor value) => + { + if (m_ColorPickerPopupDataContext != null) + { + m_ColorPickerPopupDataContext.Value = (ushort)value.RowId; + m_ColorPickerPopupDataContext = null; + m_PluginConfiguration.Save(m_PluginData); + } + + ImGui.CloseCurrentPopup(); + }); + + ImGui.EndPopup(); + } + if (!wasStyleConsumed) + { + ImGui.PopStyleVar(); + } + + ImGui.SameLine(); + DrawRemoveButton(inheritable); + + ImGui.EndChild(); + ImGui.EndGroup(); + } + + private void DrawInheritable(string localizedStringName, InheritableReference inheritable) + { + ImGui.BeginGroup(); + ImGui.Indent(); + ImGui.BeginChild(inheritable.GetHashCode().ToString(), new Vector2(180, 47)); + + ImGui.Text(Localizer.GetString(localizedStringName, false)); + + bool isEnabled = inheritable.Behavior == InheritableBehavior.Enabled; + DrawCheckbox("IsEnabled", false, ref isEnabled, () => + { + if (isEnabled) + { + inheritable.Behavior = InheritableBehavior.Enabled; + } + else + { + inheritable.Behavior = InheritableBehavior.Disabled; + } + m_PluginConfiguration.Save(m_PluginData); + }); + + if (isEnabled) + { + ImGui.SameLine(); + DrawTextBox(localizedStringName, ref inheritable.Value, () => { m_PluginConfiguration.Save(m_PluginData); }); + } + + ImGui.SameLine(); + DrawRemoveButton(inheritable); + + ImGui.EndChild(); + ImGui.EndGroup(); + } + + private void DrawHeading(string label) + { + ImGui.TextColored(new Vector4(0.7f, 0.6f, 1f, 1f), label); + } + + private void DrawComboBox(bool isLabelVisible, bool shouldLocalizeNames, bool shouldOrderNames, ref TEnum currentValue, System.Action changed) + where TEnum : Enum + { + if (isLabelVisible) + { + ImGui.Text(Localizer.GetString(false)); + } + + var currentDisplayName = shouldLocalizeNames ? Localizer.GetString(currentValue, false) : currentValue.ToString(); + + ImGui.SetNextItemWidth(ImGui.CalcItemWidth()); + if (ImGui.BeginCombo($"###{currentValue.GetType().Name}", currentDisplayName)) + { + var displayNames = Enum.GetValues(typeof(TEnum)).Cast() + .Select(value => new { Value = value, DisplayName = shouldLocalizeNames ? Localizer.GetString(value, false) : value.ToString() }); + + if (shouldOrderNames) + { + displayNames = displayNames.OrderBy(displayEnum => displayEnum.DisplayName); + } + + foreach (var orderedDisplayName in displayNames) + { + bool isSelected = orderedDisplayName.Value.Equals(currentValue); + if (ImGui.Selectable(orderedDisplayName.DisplayName, isSelected)) + { + currentValue = orderedDisplayName.Value; + changed(); + } + + if (isSelected) + { + ImGui.SetItemDefaultFocus(); + } + + if (ImGui.IsItemHovered() && shouldLocalizeNames) + { + ImGui.SetTooltip(Localizer.GetString(orderedDisplayName.Value, true)); + } + } + + ImGui.EndCombo(); + } + + if (ImGui.IsItemHovered() && shouldLocalizeNames) + { + ImGui.SetTooltip(Localizer.GetString(currentValue, true)); + } + } + + private void DrawCheckbox(string localizedStringName, bool hasLabel, ref bool isChecked, System.Action changed) + { + if (ImGui.Checkbox(hasLabel ? Localizer.GetString(localizedStringName, false) : $"###{Localizer.GetString(localizedStringName, false)}", ref isChecked)) + { + changed(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Localizer.GetString(localizedStringName, true)); + } + } + + private void DrawColorButton(string colorId, Vector4 color, System.Action clicked) + { + ImGui.PushStyleColor(ImGuiCol.Button, color); + ImGui.PushStyleColor(ImGuiCol.ButtonHovered, color); + ImGui.PushStyleColor(ImGuiCol.ButtonActive, color); + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(0, 0)); + ImGui.PushStyleVar(ImGuiStyleVar.ItemInnerSpacing, new Vector2(0, 0)); + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0); + if (ImGui.Button($"###{colorId}", new Vector2(23, 23))) + { + clicked(); + } + ImGui.PopStyleVar(); + ImGui.PopStyleVar(); + ImGui.PopStyleVar(); + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + ImGui.PopStyleColor(); + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(colorId); + } + } + + private void DrawTextBox(string localizedStringName, ref string text, System.Action changed) + { + ImGui.SetNextItemWidth(ImGui.CalcItemWidth()); + + var oldText = text; + ImGui.InputText($"###{localizedStringName}", ref text, 1024); + if (text != oldText) + { + changed(); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Localizer.GetString(localizedStringName, true)); + } + } + + private void DrawUIColorPicker(System.Action colorSelected) + { + const int columnCount = 12; + + int currentColumn = 0; + foreach (var uiColor in UIColorHelper.UIColors) + { + if (currentColumn % columnCount != 0) + { + ImGui.SameLine(0, 0); + } + + DrawColorButton(uiColor.RowId.ToString(), UIColorHelper.ToColor(uiColor), () => { colorSelected(uiColor); }); + currentColumn++; + } + } + } +} diff --git a/PlayerTags/PluginData.cs b/PlayerTags/PluginData.cs new file mode 100644 index 0000000..5633363 --- /dev/null +++ b/PlayerTags/PluginData.cs @@ -0,0 +1,99 @@ +using Dalamud.Data; +using System; +using System.Collections.Generic; + +namespace PlayerTags +{ + public class PluginData + { + public DefaultPluginData Default; + public Tag AllTags; + public Tag AllRoleTags; + public Dictionary RoleTags; + public Dictionary JobTags; + public Tag AllCustomTags; + public List CustomTags; + + public PluginData() + { + Default = new DefaultPluginData(); + AllTags = new Tag(new LocalizedPluginString(nameof(AllTags))); + AllRoleTags = new Tag(new LocalizedPluginString(nameof(AllRoleTags))); + RoleTags = new Dictionary(); + JobTags = new Dictionary(); + AllCustomTags = new Tag(new LocalizedPluginString(nameof(AllCustomTags))); + CustomTags = new List(); + } + + public void Initialize(DataManager dataManager, PluginConfiguration pluginConfiguration) + { + Default.Initialize(dataManager); + + // Set the default changes and saved changes + AllTags.SetChanges(Default.AllTagsChanges); + AllTags.SetChanges(pluginConfiguration.AllTagsChanges); + + AllRoleTags.SetChanges(Default.AllRoleTagsChanges); + AllRoleTags.SetChanges(pluginConfiguration.AllRoleTagsChanges); + + foreach (var role in Enum.GetValues()) + { + RoleTags[role] = new Tag(new LocalizedPluginString(Localizer.GetName(role))); + + if (Default.RoleTagsChanges.TryGetValue(role, out var defaultChanges)) + { + RoleTags[role].SetChanges(defaultChanges); + } + + if (pluginConfiguration.RoleTagsChanges.TryGetValue(role, out var savedChanges)) + { + RoleTags[role].SetChanges(savedChanges); + } + } + + JobTags = new Dictionary(); + foreach ((var jobAbbreviation, var role) in Default.RolesByJobAbbreviation) + { + JobTags[jobAbbreviation] = new Tag(new LiteralPluginString(jobAbbreviation)); + + if (Default.JobTagsChanges.TryGetValue(jobAbbreviation, out var defaultChanges)) + { + JobTags[jobAbbreviation].SetChanges(defaultChanges); + } + + if (pluginConfiguration.JobTagsChanges.TryGetValue(jobAbbreviation, out var savedChanges)) + { + JobTags[jobAbbreviation].SetChanges(savedChanges); + } + } + + AllCustomTags.SetChanges(Default.AllCustomTagsChanges); + AllCustomTags.SetChanges(pluginConfiguration.AllCustomTagsChanges); + + foreach (var savedChanges in pluginConfiguration.CustomTagsChanges) + { + var tag = new Tag(new LocalizedPluginString(nameof(CustomTags))); + tag.SetChanges(savedChanges); + CustomTags.Add(tag); + } + + // Set up the inheritance heirarchy + AllRoleTags.Parent = AllTags; + foreach ((var role, var roleTag) in RoleTags) + { + roleTag.Parent = AllRoleTags; + } + + foreach ((var jobAbbreviation, var jobTag) in JobTags) + { + jobTag.Parent = RoleTags[Default.RolesByJobAbbreviation[jobAbbreviation]]; + } + + AllCustomTags.Parent = AllTags; + foreach (var tag in CustomTags) + { + tag.Parent = AllCustomTags; + } + } + } +} diff --git a/PlayerTags/Resources/Promo/Chat_1.png b/PlayerTags/Resources/Promo/Chat_1.png index 1022105..1caab16 100644 Binary files a/PlayerTags/Resources/Promo/Chat_1.png and b/PlayerTags/Resources/Promo/Chat_1.png differ diff --git a/PlayerTags/Resources/Promo/Chat_2.png b/PlayerTags/Resources/Promo/Chat_2.png new file mode 100644 index 0000000..1511f60 Binary files /dev/null and b/PlayerTags/Resources/Promo/Chat_2.png differ diff --git a/PlayerTags/Resources/Promo/Icon.png b/PlayerTags/Resources/Promo/Icon.png new file mode 100644 index 0000000..4eab0e7 Binary files /dev/null and b/PlayerTags/Resources/Promo/Icon.png differ diff --git a/PlayerTags/Resources/Promo/Nameplates_1.png b/PlayerTags/Resources/Promo/Nameplates_1.png index b9bdf66..0f42999 100644 Binary files a/PlayerTags/Resources/Promo/Nameplates_1.png and b/PlayerTags/Resources/Promo/Nameplates_1.png differ diff --git a/PlayerTags/Resources/Strings.Designer.cs b/PlayerTags/Resources/Strings.Designer.cs index 4cecfcb..b2f3a67 100644 --- a/PlayerTags/Resources/Strings.Designer.cs +++ b/PlayerTags/Resources/Strings.Designer.cs @@ -61,110 +61,119 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Color. + /// Looks up a localized string similar to All Custom. /// - public static string Loc_CustomColorConfig_IsEnabled { + public static string Loc_AllCustomTags { get { - return ResourceManager.GetString("Loc_CustomColorConfig_IsEnabled", resourceCulture); + return ResourceManager.GetString("Loc_AllCustomTags", resourceCulture); } } /// - /// Looks up a localized string similar to Enable a custom color.. + /// Looks up a localized string similar to All Roles. /// - public static string Loc_CustomColorConfig_IsEnabled_Description { + public static string Loc_AllRoleTagss { get { - return ResourceManager.GetString("Loc_CustomColorConfig_IsEnabled_Description", resourceCulture); + return ResourceManager.GetString("Loc_AllRoleTagss", resourceCulture); } } /// - /// Looks up a localized string similar to Apply to game object names. + /// Looks up a localized string similar to All. /// - public static string Loc_CustomTagConfig_FormattedGameObjectNames { + public static string Loc_AllTags { get { - return ResourceManager.GetString("Loc_CustomTagConfig_FormattedGameObjectNames", resourceCulture); + return ResourceManager.GetString("Loc_AllTags", resourceCulture); } } /// - /// Looks up a localized string similar to A list of game object names to apply the tag to, separated by commas. E.g. "Cloud Strife, Tifa Lockhart". + /// Looks up a localized string similar to Custom. /// - public static string Loc_CustomTagConfig_FormattedGameObjectNames_Description { + public static string Loc_CustomTags { get { - return ResourceManager.GetString("Loc_CustomTagConfig_FormattedGameObjectNames_Description", resourceCulture); + return ResourceManager.GetString("Loc_CustomTags", resourceCulture); } } /// - /// Looks up a localized string similar to Name. + /// Looks up a localized string similar to Game object names to apply to. /// - public static string Loc_CustomTagConfig_Name { + public static string Loc_GameObjectNamesToApplyTo { get { - return ResourceManager.GetString("Loc_CustomTagConfig_Name", resourceCulture); + return ResourceManager.GetString("Loc_GameObjectNamesToApplyTo", resourceCulture); } } /// - /// Looks up a localized string similar to The name of the tag to display.. + /// Looks up a localized string similar to A list of game object names to always apply tags to, separated by commas or semi-colons. E.g. "Cloud Strife, Tifa Lockhart".. /// - public static string Loc_CustomTagConfig_Name_Description { + public static string Loc_GameObjectNamesToApplyTo_Description { get { - return ResourceManager.GetString("Loc_CustomTagConfig_Name_Description", resourceCulture); + return ResourceManager.GetString("Loc_GameObjectNamesToApplyTo_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Free company visibility. + /// Looks up a localized string similar to Icon. /// - public static string Loc_FreeCompanyNameplateVisibility { + public static string Loc_Icon { get { - return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility", resourceCulture); + return ResourceManager.GetString("Loc_Icon", resourceCulture); } } /// - /// Looks up a localized string similar to Default. + /// Looks up a localized string similar to The icon that will be displayed in the tag.. /// - public static string Loc_FreeCompanyNameplateVisibility_Default { + public static string Loc_Icon_Description { get { - return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Default", resourceCulture); + return ResourceManager.GetString("Loc_Icon_Description", resourceCulture); } } /// - /// Looks up a localized string similar to The free company on nameplates will only be visible when the character is in a free company.. + /// Looks up a localized string similar to Enable the value of this override.. /// - public static string Loc_FreeCompanyNameplateVisibility_Default_Description { + public static string Loc_IsEnabled_Description { get { - return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Default_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsEnabled_Description", resourceCulture); } } /// - /// Looks up a localized string similar to The visibility of the free company on nameplates.. + /// Looks up a localized string similar to Icon visible in chat. /// - public static string Loc_FreeCompanyNameplateVisibility_Description { + public static string Loc_IsIconVisibleInChatOption { get { - return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInChatOption", resourceCulture); } } /// - /// Looks up a localized string similar to Never visible. + /// Looks up a localized string similar to Whether the icon is visible in the tag in chat.. /// - public static string Loc_FreeCompanyNameplateVisibility_Never { + public static string Loc_IsIconVisibleInChatOption_Description { get { - return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Never", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInChatOption_Description", resourceCulture); } } /// - /// Looks up a localized string similar to The free company on nameplates will never be visible.. + /// Looks up a localized string similar to Icon visible in nameplates. /// - public static string Loc_FreeCompanyNameplateVisibility_Never_Description { + public static string Loc_IsIconVisibleInNameplateOption { get { - return ResourceManager.GetString("Loc_FreeCompanyNameplateVisibility_Never_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsIconVisibleInNameplateOption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Whether the icon is visible in the tag in nameplates.. + /// + public static string Loc_IsIconVisibleInNameplateOption_Description { + get { + return ResourceManager.GetString("Loc_IsIconVisibleInNameplateOption_Description", resourceCulture); } } @@ -187,92 +196,245 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Data element. + /// Looks up a localized string similar to Text italic. /// - public static string Loc_NameplateElement { + public static string Loc_IsTextItalicOption { get { - return ResourceManager.GetString("Loc_NameplateElement", resourceCulture); + return ResourceManager.GetString("Loc_IsTextItalicOption", resourceCulture); } } /// - /// Looks up a localized string similar to A data element on nameplates.. + /// Looks up a localized string similar to Whether the text in the tag is italic.. /// - public static string Loc_NameplateElement_Description { + public static string Loc_IsTextItalicOption_Description { get { - return ResourceManager.GetString("Loc_NameplateElement_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsTextItalicOption_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Free company. + /// Looks up a localized string similar to Text visible in chat. /// - public static string Loc_NameplateElement_FreeCompany { + public static string Loc_IsTextVisibleInChatOption { get { - return ResourceManager.GetString("Loc_NameplateElement_FreeCompany", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInChatOption", resourceCulture); } } /// - /// Looks up a localized string similar to The free company on nameplates.. + /// Looks up a localized string similar to Whether the text is visible in the tag in chat.. /// - public static string Loc_NameplateElement_FreeCompany_Description { + public static string Loc_IsTextVisibleInChatOption_Description { get { - return ResourceManager.GetString("Loc_NameplateElement_FreeCompany_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInChatOption_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Name. + /// Looks up a localized string similar to Text visible in nameplates. /// - public static string Loc_NameplateElement_Name { + public static string Loc_IsTextVisibleInNameplateOption { get { - return ResourceManager.GetString("Loc_NameplateElement_Name", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInNameplateOption", resourceCulture); } } /// - /// Looks up a localized string similar to The name on nameplates.. + /// Looks up a localized string similar to Whether the text is visible in the tag in nameplates.. /// - public static string Loc_NameplateElement_Name_Description { + public static string Loc_IsTextVisibleInNameplateOption_Description { get { - return ResourceManager.GetString("Loc_NameplateElement_Name_Description", resourceCulture); + return ResourceManager.GetString("Loc_IsTextVisibleInNameplateOption_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Title. + /// Looks up a localized string similar to Free company visibility. /// - public static string Loc_NameplateElement_Title { + public static string Loc_NameplateFreeCompanyVisibility { get { - return ResourceManager.GetString("Loc_NameplateElement_Title", resourceCulture); + return ResourceManager.GetString("Loc_NameplateFreeCompanyVisibility", resourceCulture); } } /// - /// Looks up a localized string similar to The title on nameplates.. + /// Looks up a localized string similar to Default. /// - public static string Loc_NameplateElement_Title_Description { + public static string Loc_NameplateFreeCompanyVisibility_Default { get { - return ResourceManager.GetString("Loc_NameplateElement_Title_Description", resourceCulture); + return ResourceManager.GetString("Loc_NameplateFreeCompanyVisibility_Default", resourceCulture); } } /// - /// Looks up a localized string similar to Role. + /// Looks up a localized string similar to The free company on nameplates will only be visible when the character is in a free company.. /// - public static string Loc_Role { + public static string Loc_NameplateFreeCompanyVisibility_Default_Description { get { - return ResourceManager.GetString("Loc_Role", resourceCulture); + return ResourceManager.GetString("Loc_NameplateFreeCompanyVisibility_Default_Description", resourceCulture); } } /// - /// Looks up a localized string similar to A character role.. + /// Looks up a localized string similar to Never visible. /// - public static string Loc_Role_Description { + public static string Loc_NameplateFreeCompanyVisibility_Never { get { - return ResourceManager.GetString("Loc_Role_Description", resourceCulture); + return ResourceManager.GetString("Loc_NameplateFreeCompanyVisibility_Never", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The free company on nameplates will never be visible.. + /// + public static string Loc_NameplateFreeCompanyVisibility_Never_Description { + get { + return ResourceManager.GetString("Loc_NameplateFreeCompanyVisibility_Never_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title position. + /// + public static string Loc_NameplateTitlePosition { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Always above name. + /// + public static string Loc_NameplateTitlePosition_AlwaysAboveName { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition_AlwaysAboveName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will always be positioned above the name.. + /// + public static string Loc_NameplateTitlePosition_AlwaysAboveName_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition_AlwaysAboveName_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Always below name. + /// + public static string Loc_NameplateTitlePosition_AlwaysBelowName { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition_AlwaysBelowName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will always be positioned below the name.. + /// + public static string Loc_NameplateTitlePosition_AlwaysBelowName_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition_AlwaysBelowName_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default. + /// + public static string Loc_NameplateTitlePosition_Default { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition_Default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will be positioned depending on the title.. + /// + public static string Loc_NameplateTitlePosition_Default_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitlePosition_Default_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Title visibility. + /// + public static string Loc_NameplateTitleVisibility { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Always visible. + /// + public static string Loc_NameplateTitleVisibility_Always { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_Always", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will always be visible, even when the character does not have a title.. + /// + public static string Loc_NameplateTitleVisibility_Always_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_Always_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Default. + /// + public static string Loc_NameplateTitleVisibility_Default { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_Default", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will only be visible when the character has a title.. + /// + public static string Loc_NameplateTitleVisibility_Default_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_Default_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Never visible. + /// + public static string Loc_NameplateTitleVisibility_Never { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_Never", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will never visible.. + /// + public static string Loc_NameplateTitleVisibility_Never_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_Never_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Only visible when it has tags. + /// + public static string Loc_NameplateTitleVisibility_WhenHasTags { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_WhenHasTags", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The title on nameplates will only be visible when it has tags.. + /// + public static string Loc_NameplateTitleVisibility_WhenHasTags_Description { + get { + return ResourceManager.GetString("Loc_NameplateTitleVisibility_WhenHasTags_Description", resourceCulture); } } @@ -285,15 +447,6 @@ namespace PlayerTags.Resources { } } - /// - /// Looks up a localized string similar to The DPS role.. - /// - public static string Loc_Role_DPS_Description { - get { - return ResourceManager.GetString("Loc_Role_DPS_Description", resourceCulture); - } - } - /// /// Looks up a localized string similar to Healer. /// @@ -303,15 +456,6 @@ namespace PlayerTags.Resources { } } - /// - /// Looks up a localized string similar to The healer role.. - /// - public static string Loc_Role_Healer_Description { - get { - return ResourceManager.GetString("Loc_Role_Healer_Description", resourceCulture); - } - } - /// /// Looks up a localized string similar to Land/Hand. /// @@ -321,15 +465,6 @@ namespace PlayerTags.Resources { } } - /// - /// Looks up a localized string similar to The land/hand role.. - /// - public static string Loc_Role_LandHand_Description { - get { - return ResourceManager.GetString("Loc_Role_LandHand_Description", resourceCulture); - } - } - /// /// Looks up a localized string similar to Tank. /// @@ -340,124 +475,7 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to The tank role.. - /// - public static string Loc_Role_Tank_Description { - get { - return ResourceManager.GetString("Loc_Role_Tank_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enabled. - /// - public static string Loc_RoleOverrideConfig_IsEnabled { - get { - return ResourceManager.GetString("Loc_RoleOverrideConfig_IsEnabled", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Enable the tag for this role.. - /// - public static string Loc_RoleOverrideConfig_IsEnabled_Description { - get { - return ResourceManager.GetString("Loc_RoleOverrideConfig_IsEnabled_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Name. - /// - public static string Loc_RoleOverrideConfig_Name { - get { - return ResourceManager.GetString("Loc_RoleOverrideConfig_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The name to use for this role when the format is set to use role names.. - /// - public static string Loc_RoleOverrideConfig_Name_Description { - get { - return ResourceManager.GetString("Loc_RoleOverrideConfig_Name_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tag format. - /// - public static string Loc_RoleTagFormat { - get { - return ResourceManager.GetString("Loc_RoleTagFormat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Abbreviated job name. - /// - public static string Loc_RoleTagFormat_AbbreviatedJobName { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_AbbreviatedJobName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The tag will appear as an abbreviated job name, e.g. SAM, WHM, GNB.. - /// - public static string Loc_RoleTagFormat_AbbreviatedJobName_Description { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_AbbreviatedJobName_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The format that the role tag should be displayed as.. - /// - public static string Loc_RoleTagFormat_Description { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Job name. - /// - public static string Loc_RoleTagFormat_JobName { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_JobName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The tag will appear as a job name in English, e.g. Samurai, White Mage, Gunbreaker.. - /// - public static string Loc_RoleTagFormat_JobName_Description { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_JobName_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name. - /// - public static string Loc_RoleTagFormat_RoleName { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_RoleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The tag will appear as the configured role name, e.g. DPS, Healer, Tank.. - /// - public static string Loc_RoleTagFormat_RoleName_Description { - get { - return ResourceManager.GetString("Loc_RoleTagFormat_RoleName_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add custom tag. + /// Looks up a localized string similar to Add a custom tag. /// public static string Loc_Static_AddCustomTag { get { @@ -466,20 +484,11 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Chat tag. + /// Looks up a localized string similar to Add an override.. /// - public static string Loc_Static_ChatTag { + public static string Loc_Static_AddPropertyOverride_Description { get { - return ResourceManager.GetString("Loc_Static_ChatTag", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom tags. - /// - public static string Loc_Static_CustomTags { - get { - return ResourceManager.GetString("Loc_Static_CustomTags", resourceCulture); + return ResourceManager.GetString("Loc_Static_AddPropertyOverride_Description", resourceCulture); } } @@ -492,24 +501,6 @@ namespace PlayerTags.Resources { } } - /// - /// Looks up a localized string similar to General. - /// - public static string Loc_Static_General { - get { - return ResourceManager.GetString("Loc_Static_General", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Jobs. - /// - public static string Loc_Static_Jobs { - get { - return ResourceManager.GetString("Loc_Static_Jobs", resourceCulture); - } - } - /// /// Looks up a localized string similar to Nameplates. /// @@ -519,24 +510,6 @@ namespace PlayerTags.Resources { } } - /// - /// Looks up a localized string similar to Nameplate tag. - /// - public static string Loc_Static_NameplateTag { - get { - return ResourceManager.GetString("Loc_Static_NameplateTag", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No custom tags added.. - /// - public static string Loc_Static_NoCustomTagsAdded { - get { - return ResourceManager.GetString("Loc_Static_NoCustomTagsAdded", resourceCulture); - } - } - /// /// Looks up a localized string similar to Player Tags. /// @@ -547,7 +520,7 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Remove custom tag. + /// Looks up a localized string similar to Remove this custom tag. /// public static string Loc_Static_RemoveCustomTag { get { @@ -556,272 +529,173 @@ namespace PlayerTags.Resources { } /// - /// Looks up a localized string similar to Role and job tags. + /// Looks up a localized string similar to Remove this override. The value will be inherited.. /// - public static string Loc_Static_RoleAndJobTags { + public static string Loc_Static_RemovePropertyOverride_Description { get { - return ResourceManager.GetString("Loc_Static_RoleAndJobTags", resourceCulture); + return ResourceManager.GetString("Loc_Static_RemovePropertyOverride_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Roles. + /// Looks up a localized string similar to Tags. /// - public static string Loc_Static_Roles { + public static string Loc_Static_Tags { get { - return ResourceManager.GetString("Loc_Static_Roles", resourceCulture); + return ResourceManager.GetString("Loc_Static_Tags", resourceCulture); } } /// - /// Looks up a localized string similar to String position. + /// Looks up a localized string similar to This plugin can modify nameplates. When combined with other plugins that modify nameplates, you are likely to see unexpected behavior.. /// - public static string Loc_StringPosition { + public static string Loc_Static_WarningMessage { get { - return ResourceManager.GetString("Loc_StringPosition", resourceCulture); + return ResourceManager.GetString("Loc_Static_WarningMessage", resourceCulture); } } /// /// Looks up a localized string similar to After. /// - public static string Loc_StringPosition_After { + public static string Loc_TagPosition_After { get { - return ResourceManager.GetString("Loc_StringPosition_After", resourceCulture); + return ResourceManager.GetString("Loc_TagPosition_After", resourceCulture); } } /// - /// Looks up a localized string similar to The tag will be positioned after the data element.. + /// Looks up a localized string similar to Display the tag after the target element.. /// - public static string Loc_StringPosition_After_Description { + public static string Loc_TagPosition_After_Description { get { - return ResourceManager.GetString("Loc_StringPosition_After_Description", resourceCulture); + return ResourceManager.GetString("Loc_TagPosition_After_Description", resourceCulture); } } /// /// Looks up a localized string similar to Before. /// - public static string Loc_StringPosition_Before { + public static string Loc_TagPosition_Before { get { - return ResourceManager.GetString("Loc_StringPosition_Before", resourceCulture); + return ResourceManager.GetString("Loc_TagPosition_Before", resourceCulture); } } /// - /// Looks up a localized string similar to The tag will be positioned before the data element.. + /// Looks up a localized string similar to Display the tag before the target element.. /// - public static string Loc_StringPosition_Before_Description { + public static string Loc_TagPosition_Before_Description { get { - return ResourceManager.GetString("Loc_StringPosition_Before_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The position in a string where tags will be displayed.. - /// - public static string Loc_StringPosition_Description { - get { - return ResourceManager.GetString("Loc_StringPosition_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to None. - /// - public static string Loc_StringPosition_None { - get { - return ResourceManager.GetString("Loc_StringPosition_None", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The tag will not be positioned in the string.. - /// - public static string Loc_StringPosition_None_Description { - get { - return ResourceManager.GetString("Loc_StringPosition_None_Description", resourceCulture); + return ResourceManager.GetString("Loc_TagPosition_Before_Description", resourceCulture); } } /// /// Looks up a localized string similar to Replace. /// - public static string Loc_StringPosition_Replace { + public static string Loc_TagPosition_Replace { get { - return ResourceManager.GetString("Loc_StringPosition_Replace", resourceCulture); + return ResourceManager.GetString("Loc_TagPosition_Replace", resourceCulture); } } /// - /// Looks up a localized string similar to The tag will replace its data element.. + /// Looks up a localized string similar to Replace the target element with the tag.. /// - public static string Loc_StringPosition_Replace_Description { + public static string Loc_TagPosition_Replace_Description { get { - return ResourceManager.GetString("Loc_StringPosition_Replace_Description", resourceCulture); + return ResourceManager.GetString("Loc_TagPosition_Replace_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Title position. + /// Looks up a localized string similar to Tag position in chat. /// - public static string Loc_TitleNameplatePosition { + public static string Loc_TagPositionInChat { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition", resourceCulture); + return ResourceManager.GetString("Loc_TagPositionInChat", resourceCulture); } } /// - /// Looks up a localized string similar to Always above the name. + /// Looks up a localized string similar to Where the tag should be positioned in chat.. /// - public static string Loc_TitleNameplatePosition_AlwaysAboveName { + public static string Loc_TagPositionInChat_Description { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysAboveName", resourceCulture); + return ResourceManager.GetString("Loc_TagPositionInChat_Description", resourceCulture); } } /// - /// Looks up a localized string similar to The title on nameplates will always be positioned above the name.. + /// Looks up a localized string similar to Tag position in chat. /// - public static string Loc_TitleNameplatePosition_AlwaysAboveName_Description { + public static string Loc_TagPositionInNameplates { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysAboveName_Description", resourceCulture); + return ResourceManager.GetString("Loc_TagPositionInNameplates", resourceCulture); } } /// - /// Looks up a localized string similar to Always below the name. + /// Looks up a localized string similar to Where the tag should be positioned in nameplates.. /// - public static string Loc_TitleNameplatePosition_AlwaysBelowName { + public static string Loc_TagPositionInNameplates_Description { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysBelowName", resourceCulture); + return ResourceManager.GetString("Loc_TagPositionInNameplates_Description", resourceCulture); } } /// - /// Looks up a localized string similar to The title on nameplates will always be positioned below the name.. + /// Looks up a localized string similar to Tag target in chat. /// - public static string Loc_TitleNameplatePosition_AlwaysBelowName_Description { + public static string Loc_TagTargetInNameplates { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_AlwaysBelowName_Description", resourceCulture); + return ResourceManager.GetString("Loc_TagTargetInNameplates", resourceCulture); } } /// - /// Looks up a localized string similar to Default. + /// Looks up a localized string similar to The element that the tag should target in nameplates.. /// - public static string Loc_TitleNameplatePosition_Default { + public static string Loc_TagTargetInNameplates_Description { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_Default", resourceCulture); + return ResourceManager.GetString("Loc_TagTargetInNameplates_Description", resourceCulture); } } /// - /// Looks up a localized string similar to The title on nameplates will be positioned depending on the title.. + /// Looks up a localized string similar to Text. /// - public static string Loc_TitleNameplatePosition_Default_Description { + public static string Loc_Text { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_Default_Description", resourceCulture); + return ResourceManager.GetString("Loc_Text", resourceCulture); } } /// - /// Looks up a localized string similar to The position of the title on nameplates.. + /// Looks up a localized string similar to The text that will be displayed in the tag.. /// - public static string Loc_TitleNameplatePosition_Description { + public static string Loc_Text_Description { get { - return ResourceManager.GetString("Loc_TitleNameplatePosition_Description", resourceCulture); + return ResourceManager.GetString("Loc_Text_Description", resourceCulture); } } /// - /// Looks up a localized string similar to Title visibility. + /// Looks up a localized string similar to Text color. /// - public static string Loc_TitleNameplateVisibility { + public static string Loc_TextColorOption { get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility", resourceCulture); + return ResourceManager.GetString("Loc_TextColorOption", resourceCulture); } } /// - /// Looks up a localized string similar to Always. + /// Looks up a localized string similar to The color of the text in the tag.. /// - public static string Loc_TitleNameplateVisibility_Always { + public static string Loc_TextColorOption_Description { get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Always", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The title on nameplates will always be visible, even when the character does not have a title.. - /// - public static string Loc_TitleNameplateVisibility_Always_Description { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Always_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Default. - /// - public static string Loc_TitleNameplateVisibility_Default { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Default", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The title on nameplates will only be visible when the character has a title.. - /// - public static string Loc_TitleNameplateVisibility_Default_Description { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Default_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The visibility of the title on nameplates.. - /// - public static string Loc_TitleNameplateVisibility_Description { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Never. - /// - public static string Loc_TitleNameplateVisibility_Never { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Never", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The title on nameplates will never visible.. - /// - public static string Loc_TitleNameplateVisibility_Never_Description { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_Never_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to When it has tags. - /// - public static string Loc_TitleNameplateVisibility_WhenHasTags { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_WhenHasTags", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The title on nameplates will only be visible when it has tags.. - /// - public static string Loc_TitleNameplateVisibility_WhenHasTags_Description { - get { - return ResourceManager.GetString("Loc_TitleNameplateVisibility_WhenHasTags_Description", resourceCulture); + return ResourceManager.GetString("Loc_TextColorOption_Description", resourceCulture); } } } diff --git a/PlayerTags/Resources/Strings.resx b/PlayerTags/Resources/Strings.resx index 00c1356..72a6a24 100644 --- a/PlayerTags/Resources/Strings.resx +++ b/PlayerTags/Resources/Strings.resx @@ -120,256 +120,241 @@ Player Tags - - General - - - Development - - - Custom tags - - - Add custom tag - - - Remove custom tag - - - No custom tags added. - - - Role and job tags - - - Roles - - - Jobs - - - Chat tag - - - Nameplate tag + + This plugin can modify nameplates. When combined with other plugins that modify nameplates, you are likely to see unexpected behavior. Nameplates + + Free company visibility + + + Default + + + The free company on nameplates will only be visible when the character is in a free company. + + + Never visible + + + The free company on nameplates will never be visible. + + + Title visibility + + + Always visible + + + The title on nameplates will always be visible, even when the character does not have a title. + + + Default + + + The title on nameplates will only be visible when the character has a title. + + + Never visible + + + The title on nameplates will never visible. + + + Only visible when it has tags + + + The title on nameplates will only be visible when it has tags. + + + Title position + + + Always above name + + + The title on nameplates will always be positioned above the name. + + + Always below name + + + The title on nameplates will always be positioned below the name. + + + Default + + + The title on nameplates will be positioned depending on the title. + + + Free company + + + The free company element on nameplates. + + + Name + + + The name element on nameplates. + + + Title + + + The title element on nameplates. + + + Development + Randomly generate player names Use tags to replace every player's name with a randomly generated one. Helpful for preserving anonymity when taking screenshots. - - Enabled + + Tags - - Enable the tag for this role. + + All - - Name - - - The name to use for this role when the format is set to use role names. - - - Color - - - Enable a custom color. - - - Name - - - The name of the tag to display. - - - Apply to game object names - - - A list of game object names to apply the tag to, separated by commas. E.g. "Cloud Strife, Tifa Lockhart" - - - Free company visibility - - - The visibility of the free company on nameplates. - - - Default - - - The free company on nameplates will only be visible when the character is in a free company. - - - Never visible - - - The free company on nameplates will never be visible. - - - Data element - - - A data element on nameplates. - - - Free company - - - The free company on nameplates. - - - Name - - - The name on nameplates. - - - Title - - - The title on nameplates. - - - Tag format - - - The format that the role tag should be displayed as. - - - Abbreviated job name - - - Job name - - - The tag will appear as an abbreviated job name, e.g. SAM, WHM, GNB. - - - The tag will appear as a job name in English, e.g. Samurai, White Mage, Gunbreaker. - - - Role name - - - The tag will appear as the configured role name, e.g. DPS, Healer, Tank. - - - Role - - - A character role. - - - DPS - - - The DPS role. - - - Healer - - - The healer role. + + All Roles Land/Hand - - The land/hand role. - Tank - - The tank role. + + Healer - - String position + + DPS - - The position in a string where tags will be displayed. + + All Custom - + + Custom + + + Enable the value of this override. + + + Add an override. + + + Remove this override. The value will be inherited. + + + Add a custom tag + + + Remove this custom tag + + + + Icon + + + The icon that will be displayed in the tag. + + + Icon visible in chat + + + Whether the icon is visible in the tag in chat. + + + Icon visible in nameplates + + + Whether the icon is visible in the tag in nameplates. + + + + Text + + + The text that will be displayed in the tag. + + + Text color + + + The color of the text in the tag. + + + Text italic + + + Whether the text in the tag is italic. + + + Text visible in chat + + + Whether the text is visible in the tag in chat. + + + Text visible in nameplates + + + Whether the text is visible in the tag in nameplates. + + + + Tag position in chat + + + Where the tag should be positioned in chat. + + + Tag position in nameplates + + + Where the tag should be positioned in nameplates. + + + Tag target in nameplates + + + The element that the tag should target in nameplates. + + + + Game object names to apply to + + + A list of game object names to always apply tags to, separated by commas or semi-colons. E.g. "Cloud Strife, Tifa Lockhart". + + + After - - The tag will be positioned after the data element. + + Display the tag after the target element. - + Before - - The tag will be positioned before the data element. + + Display the tag before the target element. - - None - - - The tag will not be positioned in the string. - - + Replace - - The tag will replace its data element. + + Replace the target element with the tag. - - Title position - - - The position of the title on nameplates. - - - Always above the name - - - The title on nameplates will always be positioned above the name. - - - Always below the name - - - The title on nameplates will always be positioned below the name. - - - Default - - - The title on nameplates will be positioned depending on the title. - - - Title visibility - - - The visibility of the title on nameplates. - - - Always - - - The title on nameplates will always be visible, even when the character does not have a title. - - - Default - - - The title on nameplates will only be visible when the character has a title. - - - Never - - - The title on nameplates will never visible. - - - When it has tags - - - The title on nameplates will only be visible when it has tags. + + + Enabled \ No newline at end of file diff --git a/PlayerTags/Resources/Words/Adjectives.txt b/PlayerTags/Resources/Words/Adjectives.txt index b517add..7341fb6 100644 --- a/PlayerTags/Resources/Words/Adjectives.txt +++ b/PlayerTags/Resources/Words/Adjectives.txt @@ -189,6 +189,7 @@ beta better bewildered bewitched +biblical big biggish bigheaded diff --git a/PlayerTags/Config/Role.cs b/PlayerTags/Role.cs similarity index 75% rename from PlayerTags/Config/Role.cs rename to PlayerTags/Role.cs index c13e54a..e1dc976 100644 --- a/PlayerTags/Config/Role.cs +++ b/PlayerTags/Role.cs @@ -1,4 +1,4 @@ -namespace PlayerTags.Config +namespace PlayerTags { public enum Role { diff --git a/PlayerTags/Tag.cs b/PlayerTags/Tag.cs new file mode 100644 index 0000000..4e55769 --- /dev/null +++ b/PlayerTags/Tag.cs @@ -0,0 +1,140 @@ +using Dalamud.Game.Text.SeStringHandling; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace PlayerTags +{ + public class Tag + { + public IPluginString Name { get; init; } + + private Tag? m_Parent = null; + public Tag? Parent + { + get => m_Parent; + set + { + if (m_Parent != value) + { + if (m_Parent != null) + { + if (m_Parent.Children.Contains(this)) + { + m_Parent.Children.Remove(this); + } + } + + m_Parent = value; + if (m_Parent != null) + { + m_Parent.Children.Add(this); + foreach ((var name, IInheritable inheritable) in Inheritables) + { + inheritable.Parent = m_Parent.Inheritables[name]; + } + } + } + } + } + + public List Children { get; } = new List(); + + private Dictionary? m_Inheritables = null; + public Dictionary Inheritables + { + get + { + if (m_Inheritables == null) + { + m_Inheritables = new Dictionary(); + + var inheritableFields = GetType().GetFields().Where(field => typeof(IInheritable).IsAssignableFrom(field.FieldType)); + foreach (var inheritableField in inheritableFields) + { + IInheritable? inheritable = inheritableField.GetValue(this) as IInheritable; + if (inheritable != null) + { + Inheritables[inheritableField.Name] = inheritable; + } + } + } + + return m_Inheritables!; + } + } + + public InheritableValue Icon = new InheritableValue(BitmapFontIcon.Aethernet); + public InheritableValue IsIconVisibleInChat = new InheritableValue(false); + public InheritableValue IsIconVisibleInNameplates = new InheritableValue(false); + + public InheritableReference Text = new InheritableReference(""); + public InheritableValue TextColor = new InheritableValue(6); + public InheritableValue IsTextItalic = new InheritableValue(false); + public InheritableValue IsTextVisibleInChat = new InheritableValue(false); + public InheritableValue IsTextVisibleInNameplates = new InheritableValue(false); + + public InheritableValue TagPositionInChat = new InheritableValue(TagPosition.Before); + public InheritableValue TagPositionInNameplates = new InheritableValue(TagPosition.Before); + public InheritableValue TagTargetInNameplates = new InheritableValue(NameplateElement.Name); + + public InheritableReference GameObjectNamesToApplyTo = new InheritableReference(""); + + private string[] CleanGameObjectNamesToApplyTo + { + get + { + if (GameObjectNamesToApplyTo == null || GameObjectNamesToApplyTo.InheritedValue == null) + { + return new string[] { }; + } + + return GameObjectNamesToApplyTo.InheritedValue.Split(';', ',').Select(gameObjectName => gameObjectName.ToLower().Trim()).ToArray(); + } + } + + public Tag(IPluginString name) + { + Name = name; + } + + public bool IncludesGameObjectNameToApplyTo(string gameObjectName) + { + return CleanGameObjectNamesToApplyTo.Contains(gameObjectName.ToLower()); + } + + public Dictionary GetChanges(Dictionary? defaultChanges = null) + { + Dictionary changes = new Dictionary(); + + foreach ((var name, var inheritable) in Inheritables) + { + // If there's a default for this name, only set the value if it's different from the default + if (defaultChanges != null && defaultChanges.TryGetValue(name, out var defaultInheritableData)) + { + var inheritableData = inheritable.GetData(); + if (inheritableData.Behavior != defaultInheritableData.Behavior || + !inheritableData.Value.Equals(defaultInheritableData.Value)) + { + changes[name] = inheritable.GetData(); + } + } + // If there's no default, then only set the value if it's not inherited + else if (inheritable.Behavior != InheritableBehavior.Inherit) + { + changes[name] = inheritable.GetData(); + } + } + + return changes; + } + + public void SetChanges(Dictionary changes) + { + foreach ((var name, var inheritableData) in changes) + { + Inheritables[name].SetData(inheritableData); + } + } + } +} diff --git a/PlayerTags/TagPosition.cs b/PlayerTags/TagPosition.cs new file mode 100644 index 0000000..44ae941 --- /dev/null +++ b/PlayerTags/TagPosition.cs @@ -0,0 +1,9 @@ +namespace PlayerTags +{ + public enum TagPosition + { + Before, + After, + Replace + } +} diff --git a/PlayerTags/TagTarget.cs b/PlayerTags/TagTarget.cs new file mode 100644 index 0000000..42a5429 --- /dev/null +++ b/PlayerTags/TagTarget.cs @@ -0,0 +1,8 @@ +namespace PlayerTags +{ + public enum TagTarget + { + Chat, + Nameplate + } +}