From 3f0a533b071e2af59ce1725e919277cbc70f6eb5 Mon Sep 17 00:00:00 2001 From: Pilzinsel64 Date: Wed, 21 Sep 2022 12:10:36 +0200 Subject: [PATCH] always remove own player link terminator & workaround for List.Remove() not working as expected --> Fix ExtraChat compatibility --- PlayerTags/Extensions.cs | 41 +++++++++++++++++++++ PlayerTags/Features/ChatTagTargetFeature.cs | 37 +++++++++++++------ PlayerTags/Features/TagTargetFeature.cs | 2 +- 3 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 PlayerTags/Extensions.cs diff --git a/PlayerTags/Extensions.cs b/PlayerTags/Extensions.cs new file mode 100644 index 0000000..964b8e5 --- /dev/null +++ b/PlayerTags/Extensions.cs @@ -0,0 +1,41 @@ +using Dalamud.Game.Text.SeStringHandling; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PlayerTags +{ + internal static class Extensions + { + /// + /// Removes a Payload from a given SeString. + /// Using SeString.Payloads.Remove() does not use the reference to compare for some reason. Tis is a workaround. + /// + /// + /// + public static void Remove(this SeString seString, Payload payload) + { + Remove(seString.Payloads, payload); + } + + /// + /// Removes a Payload from a given list. + /// Using List.Remove() does not use the reference to compare for some reason. Tis is a workaround. + /// + /// + /// + public static void Remove(this List payloads, Payload payload) + { + for (int i = 0; i < payloads.Count; i++) + { + if (ReferenceEquals(payloads[i], payload)) + { + payloads.RemoveAt(i); + break; + } + } + } + } +} diff --git a/PlayerTags/Features/ChatTagTargetFeature.cs b/PlayerTags/Features/ChatTagTargetFeature.cs index 6cdebc6..22678ba 100644 --- a/PlayerTags/Features/ChatTagTargetFeature.cs +++ b/PlayerTags/Features/ChatTagTargetFeature.cs @@ -43,6 +43,8 @@ namespace PlayerTags.Features /// public PlayerPayload? PlayerPayload { get; init; } + public RawPayload LinkTerminatorPayload { get; init; } + public Payload? PlayerNamePayload { get @@ -59,6 +61,14 @@ namespace PlayerTags.Features } } + public bool IsLocalPlayer + { + get + { + return GetMatchTextInternal() == PluginServices.ClientState.LocalPlayer.Name.TextValue; + } + } + public StringMatch(SeString seString) { SeString = seString; @@ -159,7 +169,7 @@ namespace PlayerTags.Features else if (payload is RawPayload rawPayload) { if (defaultRawPayload.SequenceEqual(rawPayload.Data)) - finishCurrentMatch(); + finishCurrentMatch(rawPayload); } else { @@ -169,9 +179,9 @@ namespace PlayerTags.Features } // Finally finish, if not closed by RawPayload - finishCurrentMatch(); + finishCurrentMatch(null); - void finishCurrentMatch() + void finishCurrentMatch(RawPayload linkTerminatorPayload) { if (curPlayerPayload.TryPop(out PlayerPayload playerPayload)) { @@ -180,6 +190,7 @@ namespace PlayerTags.Features { GameObject = gameObject, PlayerPayload = playerPayload, + LinkTerminatorPayload = linkTerminatorPayload, DisplayTextPayloads = curRefPayloads.Pop() }; stringMatches.Add(stringMatch); @@ -299,13 +310,13 @@ namespace PlayerTags.Features // Add the Link Terminator to end the Player Link. This should be done behind the Text Payload (display text). // Normally used to end PlayerPayload linking. But for the own player it has no affect. Anyway, use it, just because. Maybe it's needed in the future somewhere else. - //seString.Payloads.Insert(++playerPayloadIndex, RawPayload.LinkTerminator); + seString.Payloads.Insert(++playerPayloadIndex, RawPayload.LinkTerminator); // Remove TextPayload - //seString.Payloads.Remove(playerTextPayload); + //seString.Remove(playerTextPayload); // I M P O R T A N T N O T I C E: - // The PlayerPayload is now just temporary. We keep the TextPayload don't add the LinkTerminator. + // The PlayerPayload is now just temporary. We keep the TextPayload. // The PayerPayload gets removed at the ChatTagTargetFeature at the end and the TextPayload will be keeped there. } } @@ -405,13 +416,15 @@ namespace PlayerTags.Features } ApplyStringChanges(message, stringChanges, stringMatch.DisplayTextPayloads, stringMatch.PlayerNamePayload); - } - // Replace PlayerPayloads of your own character with TextPayloads - foreach (var payload in message.Payloads.ToArray()) - { - if (payload is PlayerPayload playerPayload && playerPayload.PlayerName.Contains(PluginServices.ClientState.LocalPlayer.Name.TextValue)) - message.Payloads.Remove(payload); + // Remove PlayerPayload and LinkTerminator if it's your own character (they just got added temporary) + if (stringMatch.IsLocalPlayer) + { + if (stringMatch.PlayerPayload != null) + message.Remove(stringMatch.PlayerPayload); + if (stringMatch.LinkTerminatorPayload != null) + message.Remove(stringMatch.LinkTerminatorPayload); + } } } } diff --git a/PlayerTags/Features/TagTargetFeature.cs b/PlayerTags/Features/TagTargetFeature.cs index 34255c0..eb2be97 100644 --- a/PlayerTags/Features/TagTargetFeature.cs +++ b/PlayerTags/Features/TagTargetFeature.cs @@ -342,7 +342,7 @@ namespace PlayerTags.Features { var anchorPayloadIndex = seString.Payloads.IndexOf(anchorReplace); seString.Payloads.InsertRange(anchorPayloadIndex, payloads.Payloads); - seString.Payloads.Remove(anchorReplace); + seString.Remove(anchorReplace); } else {