diff --git a/PlayerTags.sln b/PlayerTags.sln index 0219690..d0f9aff 100644 --- a/PlayerTags.sln +++ b/PlayerTags.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 17.3.32929.385 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlayerTags", "PlayerTags\PlayerTags.csproj", "{13C812E9-0D42-4B95-8646-40EEBF30636F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pilz.Dalamud", "..\Pilz.Dalamud\Pilz.Dalamud\Pilz.Dalamud.csproj", "{A92D2FFC-FDB8-4F28-B5DD-4A1B3EB0B1BB}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -17,10 +15,6 @@ Global {13C812E9-0D42-4B95-8646-40EEBF30636F}.Debug|x64.Build.0 = Debug|x64 {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.ActiveCfg = Release|x64 {13C812E9-0D42-4B95-8646-40EEBF30636F}.Release|x64.Build.0 = Release|x64 - {A92D2FFC-FDB8-4F28-B5DD-4A1B3EB0B1BB}.Debug|x64.ActiveCfg = Debug|x64 - {A92D2FFC-FDB8-4F28-B5DD-4A1B3EB0B1BB}.Debug|x64.Build.0 = Debug|x64 - {A92D2FFC-FDB8-4F28-B5DD-4A1B3EB0B1BB}.Release|x64.ActiveCfg = Release|x64 - {A92D2FFC-FDB8-4F28-B5DD-4A1B3EB0B1BB}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PlayerTags/Configuration/PluginConfiguration.cs b/PlayerTags/Configuration/PluginConfiguration.cs index 34cb5cf..6d3a2a9 100644 --- a/PlayerTags/Configuration/PluginConfiguration.cs +++ b/PlayerTags/Configuration/PluginConfiguration.cs @@ -1,19 +1,27 @@ using Dalamud.Configuration; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Pilz.Dalamud.ActivityContexts; using Pilz.Dalamud.Nameplates.Tools; using PlayerTags.Data; using PlayerTags.Inheritables; using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.CompilerServices; namespace PlayerTags.Configuration { [Serializable] public class PluginConfiguration : IPluginConfiguration { - public int Version { get; set; } = 1; + private const int DEFAULT_CONFIG_VERSION = 1; + + [JsonProperty] + public int RootVersion { get; private set; } = DEFAULT_CONFIG_VERSION; + public int Version { get; set; } = DEFAULT_CONFIG_VERSION; public bool IsVisible = false; [JsonProperty("GeneralOptionsV2")] @@ -24,7 +32,7 @@ namespace PlayerTags.Configuration { ActivityType.PvpDuty, new GeneralOptionsClass() } }; - public StatusIconPriorizerSettings StatusIconPriorizerSettings = new(); + public StatusIconPriorizerSettings StatusIconPriorizerSettings = new(true); public bool IsPlayerNameRandomlyGenerated = false; public bool IsCustomTagsContextMenuEnabled = true; public bool IsShowInheritedPropertiesEnabled = true; @@ -218,9 +226,56 @@ namespace PlayerTags.Configuration Identities = pluginData.Identities; - PluginServices.DalamudPluginInterface.SavePluginConfig(this); + SavePluginConfig(); + Saved?.Invoke(); } + + private void SavePluginConfig() + { + Version = DEFAULT_CONFIG_VERSION; + var configFilePath = GetConfigFilePath(); + var configFileContent = JsonConvert.SerializeObject(this, Formatting.Indented, GetJsonSettings()); + File.WriteAllText(configFilePath, configFileContent); + } + + public static PluginConfiguration LoadPluginConfig() + { + var configFilePath = GetConfigFilePath(); + object config = null; + + if (File.Exists(configFilePath)) + { + var configFileContent = File.ReadAllText(configFilePath); + config = JsonConvert.DeserializeObject(configFileContent, GetJsonSettings()); + } + else + { + // Try loading the old settings, if possible + configFilePath = PluginServices.DalamudPluginInterface.ConfigFile.FullName; + config = PluginServices.DalamudPluginInterface.GetPluginConfig(); + } + + return config as PluginConfiguration; + } + + private static string GetConfigFilePath() + { + return Path.Combine(PluginServices.DalamudPluginInterface.ConfigDirectory.FullName, "Config.json"); + } + + private static JsonSerializerSettings GetJsonSettings() + { + var jsonSettings = new JsonSerializerSettings + { + TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple, + TypeNameHandling = TypeNameHandling.Auto, + }; + + jsonSettings.Converters.Add(new StringEnumConverter()); + + return jsonSettings; + } } public class GeneralOptionsClass diff --git a/PlayerTags/Configuration/PluginConfigurationUI.cs b/PlayerTags/Configuration/PluginConfigurationUI.cs index d012e00..9f09e0f 100644 --- a/PlayerTags/Configuration/PluginConfigurationUI.cs +++ b/PlayerTags/Configuration/PluginConfigurationUI.cs @@ -1,8 +1,11 @@ using Dalamud.Configuration; using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Interface; using Dalamud.Logging; +using FFXIVClientStructs.FFXIV.Client.Game.UI; +using FFXIVClientStructs.Havok; using ImGuiNET; using Lumina.Excel.GeneratedSheets; using Pilz.Dalamud.ActivityContexts; @@ -15,6 +18,8 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Threading.Tasks; +using System.Transactions; namespace PlayerTags.Configuration { @@ -31,6 +36,7 @@ namespace PlayerTags.Configuration private PropertyProxy propertyProxy; private InheritableValue? m_ColorPickerPopupDataContext; + private Dictionary inheritableTEnumProxies = new(); public PluginConfigurationUI(PluginConfiguration config, PluginData pluginData) { @@ -697,6 +703,10 @@ namespace PlayerTags.Configuration { DrawInheritable(selectedInheritable.Inheritable.Key, false, false, inheritableJobIconSetName); } + else if (selectedInheritable.Inheritable.Value is InheritableReference> inheritableXivChatType) + { + DrawMultiselect(selectedInheritable.Inheritable.Key, inheritableXivChatType); + } else if (selectedInheritable.Inheritable.Value is InheritableReference inheritableString) { DrawInheritable(selectedInheritable.Inheritable.Key, inheritableString); @@ -1058,6 +1068,66 @@ namespace PlayerTags.Configuration ImGui.TextColored(new Vector4(0.7f, 0.6f, 1f, 1f), label); } + private void DrawMultiselect(string localizedStringName, InheritableReference> inheritable) where TEnum : Enum + { + bool isDisabled = inheritable.Behavior == InheritableBehavior.Inherit; + EnumList proxyKey = isDisabled ? inheritable.InheritedValue : inheritable.Value; + + if (isDisabled) + proxyKey = inheritable.InheritedValue; + if (proxyKey == null) + proxyKey = inheritable.Value; + + if (isDisabled) + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.25f); + + var isExpanded = ImGui.CollapsingHeader(Localizer.GetString(localizedStringName, false)); + + if (ImGui.IsItemHovered()) + ImGui.SetTooltip(Localizer.GetString(localizedStringName, true)); + + if (isDisabled) + { + ImGui.SameLine(); + ImGui.Text(Strings.Loc_Static_Inherited); + } + else + DrawRemovePropertyOverrideButton(inheritable); + + if (isExpanded) + { + bool isClicked = false; + var typeofEnum = typeof(TEnum); + EnumMultiselectProxy proxy; + + if (inheritableTEnumProxies.ContainsKey(proxyKey)) + proxy = inheritableTEnumProxies[proxyKey] as EnumMultiselectProxy; + else + { + proxy = new EnumMultiselectProxy(proxyKey); + inheritableTEnumProxies.Add(proxyKey, proxy); + } + + foreach (var entry in proxy.Entries) + { + var entryName = Enum.GetName(typeofEnum, entry.Value); + var tempval = entry.Enabled; + isClicked = ImGui.Checkbox(Localizer.GetString(entryName), ref isDisabled ? ref tempval : ref entry.Enabled); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip(Localizer.GetString(entryName, true)); + } + + if (!isDisabled && isClicked) + { + proxy.ApplyTo(proxyKey); + SaveSettings(); + } + } + + if (isDisabled) + ImGui.PopStyleVar(); + } + private void DrawComboBox(bool isLabelVisible, bool shouldLocalizeNames, bool shouldOrderNames, ref TEnum currentValue, System.Action changed) where TEnum : Enum { @@ -1278,5 +1348,42 @@ namespace PlayerTags.Configuration PveDuty, PvpDuty } + + private class EnumMultiselectProxy where TEnum : Enum + { + public List Entries { get; } = new(); + + public EnumMultiselectProxy(EnumList target) + { + foreach (TEnum value in Enum.GetValues(typeof(TEnum))) + Entries.Add(new(value, target.Contains(value))); + } + + public void ApplyTo(EnumList target) + { + foreach (var entry in Entries) + { + if (entry.Enabled) + { + if (!target.Contains(entry.Value)) + target.Add(entry.Value); + } + else if (target.Contains(entry.Value)) + target.Remove(entry.Value); + } + } + + public class Entry + { + public TEnum Value { get; set; } + public bool Enabled; + + public Entry(TEnum value, bool enabled) + { + Value = value; + Enabled = enabled; + } + } + } } } diff --git a/PlayerTags/Data/DefaultPluginData.cs b/PlayerTags/Data/DefaultPluginData.cs index 48263ae..71a43ea 100644 --- a/PlayerTags/Data/DefaultPluginData.cs +++ b/PlayerTags/Data/DefaultPluginData.cs @@ -1,5 +1,7 @@ -using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Game.Text; +using Dalamud.Game.Text.SeStringHandling; using Lumina.Excel.GeneratedSheets; +using System; using System.Collections.Generic; using System.Linq; @@ -44,6 +46,8 @@ namespace PlayerTags.Data IsVisibleForAlliancePlayers = true, IsVisibleForEnemyPlayers = true, IsVisibleForOtherPlayers = true, + + TargetChatTypes = new EnumList(Enum.GetValues()), }; AllRoleTags = new Tag() diff --git a/PlayerTags/Data/Tag.cs b/PlayerTags/Data/Tag.cs index 5f427e6..6338078 100644 --- a/PlayerTags/Data/Tag.cs +++ b/PlayerTags/Data/Tag.cs @@ -1,5 +1,7 @@ -using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Game.Text; +using Dalamud.Game.Text.SeStringHandling; using Newtonsoft.Json; +using Newtonsoft.Json.Converters; using Pilz.Dalamud.Icons; using PlayerTags.Inheritables; using PlayerTags.PluginStrings; @@ -172,6 +174,9 @@ namespace PlayerTags.Data [InheritableCategory("PlayerCategory")] public InheritableValue IsVisibleForOtherPlayers = new InheritableValue(false); + [InheritableCategory("ChatFeatureCategory")] + public InheritableReference> TargetChatTypes = new(new EnumList(Enum.GetValues())); + [JsonIgnore] public string[] IdentitiesToAddTo { diff --git a/PlayerTags/Data/XivChatTypeList.cs b/PlayerTags/Data/XivChatTypeList.cs new file mode 100644 index 0000000..e05fdb8 --- /dev/null +++ b/PlayerTags/Data/XivChatTypeList.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PlayerTags.Data +{ + public class EnumList : List where TEnum : Enum + { + public EnumList() : base() + { + } + + public EnumList(IEnumerable collection) : base(collection) + { + } + + //// this is first one '==' + //public static bool operator ==(EnumList obj1, EnumList obj2) + //{ + + //} + + //// this is second one '!=' + //public static bool operator !=(EnumList obj1, EnumList obj2) + //{ + // return !(obj1 == obj2); + //} + + public override bool Equals(object? obj) + { + var obj1 = this; + var obj2 = obj as EnumList; + + if (obj1 is not null && obj2 is not null) + { + if (obj1.Count != obj2.Count) + return false; + + for (int i = 0; i < obj1.Count; i++) + { + if (!obj1[i]?.Equals(obj2[i]) ?? true) + return false; + } + } + + return true; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + } +} diff --git a/PlayerTags/Features/ChatTagTargetFeature.cs b/PlayerTags/Features/ChatTagTargetFeature.cs index cfb29da..57d9da8 100644 --- a/PlayerTags/Features/ChatTagTargetFeature.cs +++ b/PlayerTags/Features/ChatTagTargetFeature.cs @@ -345,7 +345,7 @@ namespace PlayerTags.Features // Add the job tag if (playerCharacter.ClassJob.GameData != null && m_PluginData.JobTags.TryGetValue(playerCharacter.ClassJob.GameData.Abbreviation, out var jobTag)) { - if (jobTag.TagPositionInChat.InheritedValue != null) + if (jobTag.TagPositionInChat.InheritedValue != null && jobTag.TargetChatTypes.InheritedValue != null && jobTag.TargetChatTypes.Value.Contains(chatType)) { var payloads = GetPayloads(jobTag, stringMatch.GameObject); if (payloads.Any()) diff --git a/PlayerTags/GeneralConverter.cs b/PlayerTags/GeneralConverter.cs deleted file mode 100644 index eca30aa..0000000 --- a/PlayerTags/GeneralConverter.cs +++ /dev/null @@ -1,30 +0,0 @@ -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/Inheritables/InheritableBehavior.cs b/PlayerTags/Inheritables/InheritableBehavior.cs index 752c2e1..1691864 100644 --- a/PlayerTags/Inheritables/InheritableBehavior.cs +++ b/PlayerTags/Inheritables/InheritableBehavior.cs @@ -1,4 +1,7 @@ -namespace PlayerTags.Inheritables +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace PlayerTags.Inheritables { public enum InheritableBehavior { diff --git a/PlayerTags/Inheritables/InheritableData.cs b/PlayerTags/Inheritables/InheritableData.cs index 88d8d9b..9b95b85 100644 --- a/PlayerTags/Inheritables/InheritableData.cs +++ b/PlayerTags/Inheritables/InheritableData.cs @@ -12,7 +12,6 @@ namespace PlayerTags.Inheritables public InheritableBehavior Behavior; [JsonProperty("Value")] - [JsonConverter(typeof(GeneralConverter))] public object Value; } } diff --git a/PlayerTags/Inheritables/InheritableReference.cs b/PlayerTags/Inheritables/InheritableReference.cs index ea3c5e2..21bab63 100644 --- a/PlayerTags/Inheritables/InheritableReference.cs +++ b/PlayerTags/Inheritables/InheritableReference.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using Newtonsoft.Json.Converters; namespace PlayerTags.Inheritables { diff --git a/PlayerTags/PlayerTags.csproj b/PlayerTags/PlayerTags.csproj index b16c921..352f895 100644 --- a/PlayerTags/PlayerTags.csproj +++ b/PlayerTags/PlayerTags.csproj @@ -26,7 +26,7 @@ - + $(DalamudLibPath)FFXIVClientStructs.dll false diff --git a/PlayerTags/Plugin.cs b/PlayerTags/Plugin.cs index 97efc53..a1d6d1a 100644 --- a/PlayerTags/Plugin.cs +++ b/PlayerTags/Plugin.cs @@ -1,4 +1,5 @@ using Dalamud.Game.Command; +using Dalamud.Logging; using Dalamud.Plugin; using Dalamud.Plugin.Internal; using FFXIVClientStructs.FFXIV.Client.UI.Misc; @@ -30,7 +31,7 @@ namespace PlayerTags PluginServices.Initialize(pluginInterface); Pilz.Dalamud.PluginServices.Initialize(pluginInterface); - m_PluginConfiguration = PluginServices.DalamudPluginInterface.GetPluginConfig() as PluginConfiguration ?? new PluginConfiguration(); + m_PluginConfiguration = PluginConfiguration.LoadPluginConfig() ?? new PluginConfiguration(); m_PluginData = new PluginData(m_PluginConfiguration); m_PluginConfigurationUI = new PluginConfigurationUI(m_PluginConfiguration, m_PluginData); diff --git a/PlayerTags/Resources/Strings.Designer.cs b/PlayerTags/Resources/Strings.Designer.cs index a7e101f..7b45161 100644 --- a/PlayerTags/Resources/Strings.Designer.cs +++ b/PlayerTags/Resources/Strings.Designer.cs @@ -177,6 +177,15 @@ namespace PlayerTags.Resources { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Advanced Chat Options ähnelt. + /// + public static string Loc_ChatFeatureCategory { + get { + return ResourceManager.GetString("Loc_ChatFeatureCategory", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Custom id ähnelt. /// @@ -1617,6 +1626,24 @@ namespace PlayerTags.Resources { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Target Chat Types ähnelt. + /// + public static string Loc_TargetChatTypes { + get { + return ResourceManager.GetString("Loc_TargetChatTypes", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Defines for which chat type the chat features of this tag should be enabled for. ähnelt. + /// + public static string Loc_TargetChatTypes_Description { + get { + return ResourceManager.GetString("Loc_TargetChatTypes_Description", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Text ähnelt. /// diff --git a/PlayerTags/Resources/Strings.resx b/PlayerTags/Resources/Strings.resx index c5639a9..f5d3dda 100644 --- a/PlayerTags/Resources/Strings.resx +++ b/PlayerTags/Resources/Strings.resx @@ -657,4 +657,13 @@ The icon set to use for displaying the job icon. You can also choose the role icon set to display the role icon instead. + + Advanced Chat Options + + + Target Chat Types + + + Defines for which chat type the chat features of this tag should be enabled for. + \ No newline at end of file diff --git a/PlayerTags/packages.lock.json b/PlayerTags/packages.lock.json index d25458d..fc36ed7 100644 --- a/PlayerTags/packages.lock.json +++ b/PlayerTags/packages.lock.json @@ -14,8 +14,11 @@ "resolved": "2.1.8", "contentHash": "YqagNXs9InxmqkXzq7kLveImxnodkBEicAhydMXVp7dFjC7xb76U6zGgAax4/BWIWfZeWzr5DJyQSev31kj81A==" }, - "pilz.dalamud": { - "type": "Project" + "Pilz.Dalamud": { + "type": "Direct", + "requested": "[0.1.0, )", + "resolved": "0.1.0", + "contentHash": "n22WXrCzA+EAQHi4ve4PgTZYDzr0f0qsQ/1ApBBQjoCKJcwFox2rO692/2davRWiUQiNv9B56ikcnHocLp75tQ==" } } }