Added experimental LinkSelfInChat feature
This commit is contained in:
@@ -27,6 +27,7 @@ namespace PlayerTags.Configuration
|
||||
public bool IsPlayersTabAllianceVisible = true;
|
||||
public bool IsPlayersTabEnemiesVisible = true;
|
||||
public bool IsPlayersTabOthersVisible = false;
|
||||
public bool IsLinkSelfInChatEnabled = false;
|
||||
|
||||
[JsonProperty(TypeNameHandling = TypeNameHandling.None, ItemTypeNameHandling = TypeNameHandling.None)]
|
||||
public Dictionary<string, InheritableData> AllTagsChanges = new Dictionary<string, InheritableData>();
|
||||
|
||||
@@ -68,8 +68,9 @@ namespace PlayerTags.Configuration
|
||||
|
||||
ImGui.Spacing();
|
||||
ImGui.Spacing();
|
||||
DrawHeading(Strings.Loc_Static_Development);
|
||||
DrawHeading(Strings.Loc_Static_Experimental);
|
||||
DrawCheckbox(nameof(m_PluginConfiguration.IsPlayerNameRandomlyGenerated), true, ref m_PluginConfiguration.IsPlayerNameRandomlyGenerated, () => m_PluginConfiguration.Save(m_PluginData));
|
||||
DrawCheckbox(nameof(m_PluginConfiguration.IsLinkSelfInChatEnabled), true, ref m_PluginConfiguration.IsLinkSelfInChatEnabled, () => m_PluginConfiguration.Save(m_PluginData));
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
@@ -279,13 +280,13 @@ namespace PlayerTags.Configuration
|
||||
string itemName = tag.Name.Value;
|
||||
if (m_PluginData.CustomTags.Contains(tag))
|
||||
{
|
||||
if (tag.Text.InheritedValue != null)
|
||||
if (!string.IsNullOrWhiteSpace(tag.Text.InheritedValue))
|
||||
{
|
||||
itemName = tag.Text.InheritedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemName = "";
|
||||
itemName = Strings.Loc_Static_NoText;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,7 +567,6 @@ namespace PlayerTags.Configuration
|
||||
ImGui.SetTooltip(Strings.Loc_Static_AddPropertyOverride_Description);
|
||||
}
|
||||
|
||||
|
||||
// Render all the property overrides, and optionally allow the inherited properties to be rendered
|
||||
IEnumerable<KeyValuePair<string, IInheritable>> inheritables = tag.Inheritables;
|
||||
if (!m_PluginConfiguration.IsShowInheritedPropertiesEnabled)
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace PlayerTags.Features
|
||||
/// <summary>
|
||||
/// The matching text payload.
|
||||
/// </summary>
|
||||
public TextPayload TextPayload { get; init; }
|
||||
public TextPayload? TextPayload { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The matching game object if one exists
|
||||
@@ -38,10 +38,22 @@ namespace PlayerTags.Features
|
||||
/// </summary>
|
||||
public PlayerPayload? PlayerPayload { get; init; }
|
||||
|
||||
public StringMatch(SeString seString, TextPayload textPayload)
|
||||
public Payload? PreferredPayload
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TextPayload != null)
|
||||
{
|
||||
return TextPayload;
|
||||
}
|
||||
|
||||
return PlayerPayload;
|
||||
}
|
||||
}
|
||||
|
||||
public StringMatch(SeString seString)
|
||||
{
|
||||
SeString = seString;
|
||||
TextPayload = textPayload;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,7 +67,17 @@ namespace PlayerTags.Features
|
||||
return GameObject.Name.TextValue;
|
||||
}
|
||||
|
||||
return TextPayload.Text;
|
||||
if (TextPayload != null)
|
||||
{
|
||||
return TextPayload.Text;
|
||||
}
|
||||
|
||||
if (PlayerPayload != null)
|
||||
{
|
||||
return PlayerPayload.PlayerName;
|
||||
}
|
||||
|
||||
return SeString.TextValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,23 +140,24 @@ namespace PlayerTags.Features
|
||||
{
|
||||
var gameObject = PluginServices.ObjectTable.FirstOrDefault(gameObject => gameObject.Name.TextValue == playerPayload.PlayerName);
|
||||
|
||||
TextPayload? textPayload = null;
|
||||
|
||||
// The next payload MUST be a text payload
|
||||
if (payloadIndex + 1 < seString.Payloads.Count && seString.Payloads[payloadIndex + 1] is TextPayload textPayload)
|
||||
if (payloadIndex + 1 < seString.Payloads.Count)
|
||||
{
|
||||
var stringMatch = new StringMatch(seString, textPayload)
|
||||
{
|
||||
GameObject = gameObject,
|
||||
PlayerPayload = playerPayload
|
||||
};
|
||||
stringMatches.Add(stringMatch);
|
||||
textPayload = seString.Payloads[payloadIndex + 1] as TextPayload;
|
||||
|
||||
// Don't handle the text payload twice
|
||||
payloadIndex++;
|
||||
}
|
||||
else
|
||||
|
||||
var stringMatch = new StringMatch(seString)
|
||||
{
|
||||
PluginLog.Error("Expected payload after player payload to be a text payload but it wasn't");
|
||||
}
|
||||
GameObject = gameObject,
|
||||
PlayerPayload = playerPayload,
|
||||
TextPayload = textPayload
|
||||
};
|
||||
stringMatches.Add(stringMatch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,26 +225,7 @@ namespace PlayerTags.Features
|
||||
}
|
||||
|
||||
// An additional step to apply text color to additional locations
|
||||
if (stringMatch.GameObject is PlayerCharacter playerCharacter1)
|
||||
{
|
||||
if (m_PluginData.JobTags.TryGetValue(playerCharacter1.ClassJob.GameData.Abbreviation, out var jobTag))
|
||||
{
|
||||
if (IsTagVisible(jobTag, stringMatch.GameObject))
|
||||
{
|
||||
if (jobTag.TextColor.InheritedValue != null)
|
||||
{
|
||||
if (jobTag.IsTextColorAppliedToChatName.InheritedValue != null && jobTag.IsTextColorAppliedToChatName.InheritedValue.Value)
|
||||
{
|
||||
int payloadIndex = message.Payloads.IndexOf(stringMatch.TextPayload);
|
||||
message.Payloads.Insert(payloadIndex + 1, new UIForegroundPayload(0));
|
||||
message.Payloads.Insert(payloadIndex, (new UIForegroundPayload(jobTag.TextColor.InheritedValue.Value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stringMatch.PlayerPayload != null)
|
||||
if (stringMatch.PlayerPayload != null && stringMatch.PreferredPayload != null)
|
||||
{
|
||||
foreach (var customTag in m_PluginData.CustomTags)
|
||||
{
|
||||
@@ -233,7 +237,7 @@ namespace PlayerTags.Features
|
||||
{
|
||||
if (customTag.IsTextColorAppliedToChatName.InheritedValue != null && customTag.IsTextColorAppliedToChatName.InheritedValue.Value)
|
||||
{
|
||||
int payloadIndex = message.Payloads.IndexOf(stringMatch.TextPayload);
|
||||
int payloadIndex = message.Payloads.IndexOf(stringMatch.PreferredPayload);
|
||||
message.Payloads.Insert(payloadIndex + 1, new UIForegroundPayload(0));
|
||||
message.Payloads.Insert(payloadIndex, (new UIForegroundPayload(customTag.TextColor.InheritedValue.Value)));
|
||||
}
|
||||
@@ -241,9 +245,28 @@ namespace PlayerTags.Features
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stringMatch.GameObject is PlayerCharacter playerCharacter1)
|
||||
{
|
||||
if (m_PluginData.JobTags.TryGetValue(playerCharacter1.ClassJob.GameData.Abbreviation, out var jobTag))
|
||||
{
|
||||
if (IsTagVisible(jobTag, stringMatch.GameObject))
|
||||
{
|
||||
if (jobTag.TextColor.InheritedValue != null)
|
||||
{
|
||||
if (jobTag.IsTextColorAppliedToChatName.InheritedValue != null && jobTag.IsTextColorAppliedToChatName.InheritedValue.Value)
|
||||
{
|
||||
int payloadIndex = message.Payloads.IndexOf(stringMatch.PreferredPayload);
|
||||
message.Payloads.Insert(payloadIndex + 1, new UIForegroundPayload(0));
|
||||
message.Payloads.Insert(payloadIndex, (new UIForegroundPayload(jobTag.TextColor.InheritedValue.Value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.TextPayload);
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.PreferredPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
115
PlayerTags/Features/LinkSelfInChatFeature.cs
Normal file
115
PlayerTags/Features/LinkSelfInChatFeature.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using Dalamud.Game.ClientState.Objects.SubKinds;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Game.Text;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Logging;
|
||||
using PlayerTags.Configuration;
|
||||
using PlayerTags.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace PlayerTags.Features
|
||||
{
|
||||
public class LinkSelfInChatFeature : IDisposable
|
||||
{
|
||||
private PluginConfiguration m_PluginConfiguration;
|
||||
private PluginData m_PluginData;
|
||||
|
||||
public LinkSelfInChatFeature(PluginConfiguration pluginConfiguration, PluginData pluginData)
|
||||
{
|
||||
m_PluginConfiguration = pluginConfiguration;
|
||||
m_PluginData = pluginData;
|
||||
|
||||
PluginServices.ChatGui.ChatMessage += Chat_ChatMessage;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
PluginServices.ChatGui.ChatMessage -= Chat_ChatMessage;
|
||||
}
|
||||
|
||||
private void Chat_ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled)
|
||||
{
|
||||
if (m_PluginConfiguration.IsLinkSelfInChatEnabled)
|
||||
{
|
||||
ParsePayloads(sender);
|
||||
ParsePayloads(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParsePayloads(SeString seString)
|
||||
{
|
||||
if (PluginServices.ClientState.LocalPlayer != null)
|
||||
{
|
||||
foreach (var payload in seString.Payloads.ToArray())
|
||||
{
|
||||
if (payload is not TextPayload textPayload)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
List<TextPayload> playerTextPayloads = new List<TextPayload>();
|
||||
|
||||
var playerName = PluginServices.ClientState.LocalPlayer.Name.TextValue;
|
||||
|
||||
if (textPayload.Text == playerName)
|
||||
{
|
||||
playerTextPayloads.Add(textPayload);
|
||||
textPayload.Text = textPayload.Text;
|
||||
}
|
||||
else
|
||||
{
|
||||
var textMatchIndex = textPayload.Text.IndexOf(playerName);
|
||||
while (textMatchIndex >= 0)
|
||||
{
|
||||
var textPayloadIndex = seString.Payloads.IndexOf(payload);
|
||||
|
||||
// Chop text to the left and insert it as a new payload
|
||||
if (textMatchIndex > 0)
|
||||
{
|
||||
seString.Payloads.Insert(textPayloadIndex, new TextPayload(textPayload.Text.Substring(0, textMatchIndex)));
|
||||
|
||||
// Remove from the chopped text from the original payload
|
||||
textPayload.Text = textPayload.Text.Substring(textMatchIndex, textPayload.Text.Length - textMatchIndex);
|
||||
}
|
||||
|
||||
// This is the last reference to the local player in this payload
|
||||
if (textPayload.Text.Length == playerName.Length)
|
||||
{
|
||||
playerTextPayloads.Add(textPayload);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the new name payload and add it
|
||||
var playerTextPayload = new TextPayload(playerName);
|
||||
playerTextPayloads.Add(playerTextPayload);
|
||||
seString.Payloads.Insert(textPayloadIndex, playerTextPayload);
|
||||
|
||||
// Remove from the chopped text from the original payload
|
||||
textPayload.Text = textPayload.Text.Substring(0, playerName.Length);
|
||||
|
||||
textMatchIndex = textPayload.Text.IndexOf(playerName);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var playerTextPayload in playerTextPayloads)
|
||||
{
|
||||
// This does some dodgy shit for an unknown reason.
|
||||
// Typically when you receive a player payload followed by a text payload, it displays the text
|
||||
// and links it with the player payload. When trying to make one of these manually, it displays the player payload separately,
|
||||
// effectively doubling up the player name.
|
||||
//var playerPayload = new PlayerPayload(playerName, PluginServices.ClientState.LocalPlayer.HomeWorld.Id);
|
||||
//seString.Payloads.Insert(seString.Payloads.IndexOf(playerTextPayload), playerPayload);
|
||||
|
||||
// For now, don't follow up with a text payload. Only use a player payload.
|
||||
var playerPayload = new PlayerPayload(playerName, PluginServices.ClientState.LocalPlayer.HomeWorld.Id);
|
||||
seString.Payloads.Insert(seString.Payloads.IndexOf(playerTextPayload), playerPayload);
|
||||
seString.Payloads.Remove(playerTextPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ namespace PlayerTags
|
||||
private PluginData m_PluginData;
|
||||
private PluginConfigurationUI m_PluginConfigurationUI;
|
||||
|
||||
private LinkSelfInChatFeature m_LinkSelfInChatFeature;
|
||||
private CustomTagsContextMenuFeature m_CustomTagsContextMenuFeature;
|
||||
private NameplatesTagTargetFeature m_NameplatesTagTargetFeature;
|
||||
private ChatTagTargetFeature m_ChatTagTargetFeature;
|
||||
@@ -38,6 +39,7 @@ namespace PlayerTags
|
||||
m_PluginConfiguration.IsVisible = true;
|
||||
m_PluginConfiguration.Save(m_PluginData);
|
||||
}) { HelpMessage = "Shows the config" });
|
||||
m_LinkSelfInChatFeature = new LinkSelfInChatFeature(m_PluginConfiguration, m_PluginData);
|
||||
m_CustomTagsContextMenuFeature = new CustomTagsContextMenuFeature(m_XivCommon, m_PluginConfiguration, m_PluginData);
|
||||
m_NameplatesTagTargetFeature = new NameplatesTagTargetFeature(m_PluginConfiguration, m_PluginData);
|
||||
m_ChatTagTargetFeature = new ChatTagTargetFeature(m_PluginConfiguration, m_PluginData);
|
||||
@@ -47,7 +49,8 @@ namespace PlayerTags
|
||||
{
|
||||
m_ChatTagTargetFeature.Dispose();
|
||||
m_NameplatesTagTargetFeature.Dispose();
|
||||
m_CustomTagsContextMenuFeature.Dispose();
|
||||
m_CustomTagsContextMenuFeature.Dispose();
|
||||
m_LinkSelfInChatFeature.Dispose();
|
||||
PluginServices.CommandManager.RemoveHandler(c_CommandName);
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.OpenConfigUi -= UiBuilder_OpenConfigUi;
|
||||
PluginServices.DalamudPluginInterface.UiBuilder.Draw -= UiBuilder_Draw;
|
||||
|
||||
36
PlayerTags/Resources/Strings.Designer.cs
generated
36
PlayerTags/Resources/Strings.Designer.cs
generated
@@ -240,6 +240,24 @@ namespace PlayerTags.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Detect references to self in chat.
|
||||
/// </summary>
|
||||
public static string Loc_IsLinkSelfInChatEnabled {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_IsLinkSelfInChatEnabled", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Attempts to detect references to self in chat. This allows tags to appear in chat for yourself..
|
||||
/// </summary>
|
||||
public static string Loc_IsLinkSelfInChatEnabled_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_IsLinkSelfInChatEnabled_Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Randomly generate player names.
|
||||
/// </summary>
|
||||
@@ -1041,6 +1059,15 @@ namespace PlayerTags.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Experimental.
|
||||
/// </summary>
|
||||
public static string Loc_Static_Experimental {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_Experimental", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add '{0}' to {1}..
|
||||
/// </summary>
|
||||
@@ -1086,6 +1113,15 @@ namespace PlayerTags.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to <No text>.
|
||||
/// </summary>
|
||||
public static string Loc_Static_NoText {
|
||||
get {
|
||||
return ResourceManager.GetString("Loc_Static_NoText", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Player.
|
||||
/// </summary>
|
||||
|
||||
@@ -252,15 +252,27 @@
|
||||
<data name="Loc_Static_Development" xml:space="preserve">
|
||||
<value>Development</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Experimental" xml:space="preserve">
|
||||
<value>Experimental</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayerNameRandomlyGenerated" xml:space="preserve">
|
||||
<value>Randomly generate player names</value>
|
||||
</data>
|
||||
<data name="Loc_IsPlayerNameRandomlyGenerated_Description" xml:space="preserve">
|
||||
<value>Replace every player's name with a randomly generated one.</value>
|
||||
</data>
|
||||
<data name="Loc_IsLinkSelfInChatEnabled" xml:space="preserve">
|
||||
<value>Detect references to self in chat</value>
|
||||
</data>
|
||||
<data name="Loc_IsLinkSelfInChatEnabled_Description" xml:space="preserve">
|
||||
<value>Attempts to detect references to self in chat. This allows tags to appear in chat for yourself.</value>
|
||||
</data>
|
||||
<data name="Loc_Static_Tags" xml:space="preserve">
|
||||
<value>Tags</value>
|
||||
</data>
|
||||
<data name="Loc_Static_NoText" xml:space="preserve">
|
||||
<value><No text></value>
|
||||
</data>
|
||||
<data name="Loc_AllTags" xml:space="preserve">
|
||||
<value>All</value>
|
||||
</data>
|
||||
|
||||
Reference in New Issue
Block a user