improve position and coloring of party number prefix
This commit is contained in:
@@ -28,10 +28,7 @@ namespace PlayerTags.Features
|
||||
/// </summary>
|
||||
public SeString SeString { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The matching text payload.
|
||||
/// </summary>
|
||||
public TextPayload? TextPayload { get; init; }
|
||||
public List<Payload> DisplayTextPayloads { get; init; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The matching game object if one exists
|
||||
@@ -43,16 +40,18 @@ namespace PlayerTags.Features
|
||||
/// </summary>
|
||||
public PlayerPayload? PlayerPayload { get; init; }
|
||||
|
||||
public Payload? PreferredPayload
|
||||
public Payload? PlayerNamePayload
|
||||
{
|
||||
get
|
||||
{
|
||||
if (TextPayload != null)
|
||||
{
|
||||
return TextPayload;
|
||||
}
|
||||
Payload textPayload = null;
|
||||
string textMatch = GetMatchText();
|
||||
|
||||
return PlayerPayload;
|
||||
textPayload = DisplayTextPayloads.FirstOrDefault(n => n is TextPayload textPayload && textPayload.Text.Contains(textMatch));
|
||||
textPayload ??= PlayerPayload;
|
||||
textPayload ??= DisplayTextPayloads.FirstOrDefault();
|
||||
|
||||
return textPayload;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,11 +71,6 @@ namespace PlayerTags.Features
|
||||
return GameObject.Name.TextValue;
|
||||
}
|
||||
|
||||
if (TextPayload != null)
|
||||
{
|
||||
return TextPayload.Text;
|
||||
}
|
||||
|
||||
if (PlayerPayload != null)
|
||||
{
|
||||
return PlayerPayload.PlayerName;
|
||||
@@ -107,8 +101,8 @@ namespace PlayerTags.Features
|
||||
{
|
||||
if (m_PluginConfiguration.GeneralOptions[ActivityContextManager.CurrentActivityContext].IsApplyTagsToAllChatMessagesEnabled || Enum.IsDefined(type))
|
||||
{
|
||||
AddTagsToChat(sender);
|
||||
AddTagsToChat(message);
|
||||
AddTagsToChat(sender, type, true);
|
||||
AddTagsToChat(message, type, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,31 +133,44 @@ namespace PlayerTags.Features
|
||||
/// <returns>A list of matched game objects.</returns>
|
||||
private List<StringMatch> GetStringMatches(SeString seString)
|
||||
{
|
||||
List<StringMatch> stringMatches = new List<StringMatch>();
|
||||
List<StringMatch> stringMatches = new();
|
||||
Stack<PlayerPayload> curPlayerPayload = new();
|
||||
Stack<List<Payload>> curRefPayloads = new();
|
||||
var defaultRawPayload = RawPayload.LinkTerminator.Data;
|
||||
|
||||
for (int payloadIndex = 0; payloadIndex < seString.Payloads.Count; ++payloadIndex)
|
||||
foreach (var payload in seString.Payloads)
|
||||
{
|
||||
var payload = seString.Payloads[payloadIndex];
|
||||
|
||||
if (payload is PlayerPayload playerPayload)
|
||||
{
|
||||
curPlayerPayload.Push(playerPayload);
|
||||
curRefPayloads.Push(new List<Payload>());
|
||||
}
|
||||
else if (payload is RawPayload rawPayload)
|
||||
{
|
||||
if (defaultRawPayload.SequenceEqual(rawPayload.Data))
|
||||
finishCurrentMatch();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (curRefPayloads.TryPeek(out List<Payload> result))
|
||||
result.Add(payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Finally finish, if not closed by RawPayload
|
||||
finishCurrentMatch();
|
||||
|
||||
void finishCurrentMatch()
|
||||
{
|
||||
if (curPlayerPayload.TryPop(out PlayerPayload playerPayload))
|
||||
{
|
||||
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)
|
||||
{
|
||||
textPayload = seString.Payloads[payloadIndex + 1] as TextPayload;
|
||||
|
||||
// Don't handle the text payload twice
|
||||
payloadIndex++;
|
||||
}
|
||||
|
||||
var stringMatch = new StringMatch(seString)
|
||||
{
|
||||
GameObject = gameObject,
|
||||
PlayerPayload = playerPayload,
|
||||
TextPayload = textPayload
|
||||
DisplayTextPayloads = curRefPayloads.Pop()
|
||||
};
|
||||
stringMatches.Add(stringMatch);
|
||||
}
|
||||
@@ -172,12 +179,45 @@ namespace PlayerTags.Features
|
||||
return stringMatches;
|
||||
}
|
||||
|
||||
private void SplitOffPartyNumberPrefix(SeString sender, XivChatType type)
|
||||
{
|
||||
if (type == XivChatType.Party || type == XivChatType.Alliance)
|
||||
{
|
||||
PlayerPayload lastPlayerPayload = null;
|
||||
foreach (var payload in sender.Payloads.ToArray())
|
||||
{
|
||||
if (payload is PlayerPayload playerPayload)
|
||||
lastPlayerPayload = playerPayload;
|
||||
else if (payload is TextPayload playerNamePayload && lastPlayerPayload != null)
|
||||
{
|
||||
// Get position of player name in payload
|
||||
var indexOfPlayerName = playerNamePayload.Text.IndexOf(lastPlayerPayload.PlayerName);
|
||||
|
||||
if (indexOfPlayerName > 0)
|
||||
{
|
||||
// Split off the name from the prefix number
|
||||
var prefixPayload = new TextPayload(playerNamePayload.Text[..indexOfPlayerName]);
|
||||
playerNamePayload.Text = playerNamePayload.Text[indexOfPlayerName..];
|
||||
|
||||
// Add prefix number before the player name payload
|
||||
var playerNamePayloadIndex = sender.Payloads.IndexOf(playerNamePayload);
|
||||
sender.Payloads.Insert(playerNamePayloadIndex, prefixPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all configured tags to a chat message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to change.</param>
|
||||
private void AddTagsToChat(SeString message)
|
||||
private void AddTagsToChat(SeString message, XivChatType chatType, bool isSender)
|
||||
{
|
||||
// Split out the party/alliance number from the PlayerPayload
|
||||
if (isSender)
|
||||
SplitOffPartyNumberPrefix(message, chatType);
|
||||
|
||||
var stringMatches = GetStringMatches(message);
|
||||
foreach (var stringMatch in stringMatches)
|
||||
{
|
||||
@@ -235,7 +275,7 @@ namespace PlayerTags.Features
|
||||
}
|
||||
|
||||
// An additional step to apply text color to additional locations
|
||||
if (stringMatch.PlayerPayload != null && stringMatch.PreferredPayload != null)
|
||||
if (stringMatch.PlayerPayload != null && stringMatch.DisplayTextPayloads.Any())
|
||||
{
|
||||
Identity identity = m_PluginData.GetIdentity(stringMatch.PlayerPayload);
|
||||
foreach (var customTagId in identity.CustomTagIds)
|
||||
@@ -252,10 +292,10 @@ namespace PlayerTags.Features
|
||||
}
|
||||
|
||||
void applyTextFormatting(Tag tag)
|
||||
=> ApplyTextFormatting(stringMatch.GameObject, tag, new[] { message }, new[] { tag.IsTextColorAppliedToChatName }, stringMatch.PreferredPayload);
|
||||
=> ApplyTextFormatting(stringMatch.GameObject, tag, new[] { message }, new[] { tag.IsTextColorAppliedToChatName }, stringMatch.DisplayTextPayloads);
|
||||
}
|
||||
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.PreferredPayload);
|
||||
ApplyStringChanges(message, stringChanges, stringMatch.DisplayTextPayloads, stringMatch.PlayerNamePayload);
|
||||
}
|
||||
|
||||
// Replace PlayerPayloads of your own character with TextPayloads
|
||||
|
||||
@@ -33,12 +33,12 @@ namespace PlayerTags.Features
|
||||
{
|
||||
if (m_PluginConfiguration.GeneralOptions[activityContextManager.CurrentActivityContext].IsLinkSelfInChatEnabled)
|
||||
{
|
||||
ParsePayloads(sender);
|
||||
ParsePayloads(message);
|
||||
ParsePayloads(sender, type, true);
|
||||
ParsePayloads(message, type, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void ParsePayloads(SeString seString)
|
||||
private void ParsePayloads(SeString seString, XivChatType chatType, bool isSender)
|
||||
{
|
||||
if (PluginServices.ClientState.LocalPlayer != null)
|
||||
{
|
||||
@@ -101,7 +101,10 @@ namespace PlayerTags.Features
|
||||
// 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);
|
||||
var playerPayloadIndex = seString.Payloads.IndexOf(playerTextPayload);
|
||||
int playerPayloadIndex = seString.Payloads.IndexOf(playerTextPayload);
|
||||
|
||||
if (isSender && (chatType == XivChatType.Party || chatType == XivChatType.Alliance))
|
||||
playerPayloadIndex--;
|
||||
|
||||
// Add the Player Link Payload
|
||||
seString.Payloads.Insert(playerPayloadIndex++, playerPayload);
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace PlayerTags.Features
|
||||
/// <param name="seString">The string to apply changes to.</param>
|
||||
/// <param name="stringChanges">The changes to apply.</param>
|
||||
/// <param name="anchorPayload">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.</param>
|
||||
protected void ApplyStringChanges(SeString seString, Dictionary<TagPosition, List<Payload>> stringChanges, Payload? anchorPayload = null)
|
||||
protected void ApplyStringChanges(SeString seString, Dictionary<TagPosition, List<Payload>> stringChanges, List<Payload> anchorPayloads = null, Payload anchorReplacePayload = null)
|
||||
{
|
||||
if (stringChanges.Count == 0)
|
||||
{
|
||||
@@ -249,7 +249,7 @@ namespace PlayerTags.Features
|
||||
|
||||
List<TagPosition> tagPositionsOrdered = new List<TagPosition>();
|
||||
// If there's no anchor payload, do replaces first so that befores and afters are based on the replaced data
|
||||
if (anchorPayload == null)
|
||||
if (anchorPayloads == null || !anchorPayloads.Any())
|
||||
{
|
||||
tagPositionsOrdered.Add(TagPosition.Replace);
|
||||
}
|
||||
@@ -258,7 +258,7 @@ namespace PlayerTags.Features
|
||||
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)
|
||||
if (anchorPayloads != null && anchorPayloads.Any())
|
||||
{
|
||||
tagPositionsOrdered.Add(TagPosition.Replace);
|
||||
}
|
||||
@@ -270,8 +270,9 @@ namespace PlayerTags.Features
|
||||
AddSpacesBetweenTextPayloads(stringChanges[tagPosition], tagPosition);
|
||||
if (tagPosition == TagPosition.Before)
|
||||
{
|
||||
if (anchorPayload != null)
|
||||
if (anchorPayloads != null && anchorPayloads.Any())
|
||||
{
|
||||
var anchorPayload = anchorPayloads.First();
|
||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorPayload);
|
||||
seString.Payloads.InsertRange(anchorPayloadIndex, payloads);
|
||||
}
|
||||
@@ -282,8 +283,9 @@ namespace PlayerTags.Features
|
||||
}
|
||||
else if (tagPosition == TagPosition.After)
|
||||
{
|
||||
if (anchorPayload != null)
|
||||
if (anchorPayloads != null && anchorPayloads.Any())
|
||||
{
|
||||
var anchorPayload = anchorPayloads.Last();
|
||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorPayload);
|
||||
seString.Payloads.InsertRange(anchorPayloadIndex + 1, payloads);
|
||||
}
|
||||
@@ -294,11 +296,11 @@ namespace PlayerTags.Features
|
||||
}
|
||||
else if (tagPosition == TagPosition.Replace)
|
||||
{
|
||||
if (anchorPayload != null)
|
||||
if (anchorReplacePayload != null)
|
||||
{
|
||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorPayload);
|
||||
var anchorPayloadIndex = seString.Payloads.IndexOf(anchorReplacePayload);
|
||||
seString.Payloads.InsertRange(anchorPayloadIndex, payloads);
|
||||
seString.Payloads.Remove(anchorPayload);
|
||||
seString.Payloads.Remove(anchorReplacePayload);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -310,7 +312,7 @@ namespace PlayerTags.Features
|
||||
}
|
||||
}
|
||||
|
||||
protected void ApplyTextFormatting(GameObject gameObject, Tag tag, SeString[] destStrings, InheritableValue<bool>[] textColorApplied, Payload preferedPayload)
|
||||
protected void ApplyTextFormatting(GameObject gameObject, Tag tag, SeString[] destStrings, InheritableValue<bool>[] textColorApplied, List<Payload> preferedPayloads)
|
||||
{
|
||||
if (IsTagVisible(tag, gameObject))
|
||||
{
|
||||
@@ -355,10 +357,10 @@ namespace PlayerTags.Features
|
||||
|
||||
void applyTextFormattingPayloads(SeString destPayload, Payload startPayload, Payload endPayload)
|
||||
{
|
||||
if (preferedPayload == null)
|
||||
if (preferedPayloads == null || !preferedPayloads.Any())
|
||||
applyTextFormattingPayloadToStartAndEnd(destPayload, startPayload, endPayload);
|
||||
else
|
||||
applyTextFormattingPayloadsToSpecificPosition(destPayload, startPayload, endPayload, preferedPayload);
|
||||
applyTextFormattingPayloadsToSpecificPosition(destPayload, startPayload, endPayload, preferedPayloads);
|
||||
}
|
||||
|
||||
void applyTextFormattingPayloadToStartAndEnd(SeString destPayload, Payload startPayload, Payload endPayload)
|
||||
@@ -367,11 +369,13 @@ namespace PlayerTags.Features
|
||||
destPayload.Payloads.Add(endPayload);
|
||||
}
|
||||
|
||||
void applyTextFormattingPayloadsToSpecificPosition(SeString destPayload, Payload startPayload, Payload endPayload, Payload preferedPayload)
|
||||
void applyTextFormattingPayloadsToSpecificPosition(SeString destPayload, Payload startPayload, Payload endPayload, List<Payload> preferedPayload)
|
||||
{
|
||||
int payloadIndex = destPayload.Payloads.IndexOf(preferedPayload);
|
||||
destPayload.Payloads.Insert(payloadIndex + 1, endPayload);
|
||||
destPayload.Payloads.Insert(payloadIndex, startPayload);
|
||||
int payloadStartIndex = destPayload.Payloads.IndexOf(preferedPayloads.First());
|
||||
destPayload.Payloads.Insert(payloadStartIndex, startPayload);
|
||||
|
||||
int payloadEndIndex = destPayload.Payloads.IndexOf(preferedPayloads.Last());
|
||||
destPayload.Payloads.Insert(payloadEndIndex + 1, endPayload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user