feat: increase efficiency
This commit is contained in:
parent
09a0077623
commit
ef1ef4de5b
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Dalamud;
|
using Dalamud;
|
||||||
using Dalamud.Logging;
|
using Dalamud.Logging;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using Lumina.Excel.GeneratedSheets;
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
|
||||||
namespace NominaOcculta;
|
namespace NominaOcculta;
|
||||||
|
@ -13,37 +14,42 @@ internal class AppearanceRepository {
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
private List<ENpcBase> Npcs { get; }
|
private List<ENpcBase> Npcs { get; }
|
||||||
private List<ENpcBase> PersonalNpcs { get; } = new();
|
private List<ENpcBase> PersonalNpcs { get; } = new();
|
||||||
|
private Dictionary<uint, int> Cache { get; } = new();
|
||||||
private int Salt { get; set; } = new Random().Next();
|
private int Salt { get; set; } = new Random().Next();
|
||||||
|
|
||||||
private static readonly string[] Exclude = {
|
private static readonly string[] Exclude = {
|
||||||
"Thancred",
|
|
||||||
"Y'shtola",
|
|
||||||
"Alphinaud",
|
|
||||||
"Alisaie",
|
"Alisaie",
|
||||||
"Urianger",
|
"Alphinaud",
|
||||||
"Tataru",
|
|
||||||
"Minfilia",
|
|
||||||
"Lyse",
|
|
||||||
"Yda",
|
|
||||||
"Papalymo",
|
|
||||||
"Krile",
|
|
||||||
"Ryne",
|
|
||||||
"Estinien",
|
|
||||||
"Nanamo Ul Namo",
|
|
||||||
"G'raha Tia",
|
|
||||||
"Raubahn",
|
|
||||||
"Cid",
|
|
||||||
"Biggs",
|
|
||||||
"Wedge",
|
|
||||||
"Haurchefant",
|
|
||||||
"Merlwyb",
|
|
||||||
"Kan-E-Senna",
|
|
||||||
"Yugiri",
|
|
||||||
"Aymeric",
|
"Aymeric",
|
||||||
"Lahabrea",
|
"Biggs",
|
||||||
"Igeyorhm",
|
"Cid",
|
||||||
"Hildibrand",
|
"Estinien",
|
||||||
|
"G'raha Tia",
|
||||||
"Godbert",
|
"Godbert",
|
||||||
|
"Haurchefant",
|
||||||
|
"Hermes",
|
||||||
|
"Hildibrand",
|
||||||
|
"Hythlodaeus",
|
||||||
|
"Igeyorhm",
|
||||||
|
"Kan-E-Senna",
|
||||||
|
"Krile",
|
||||||
|
"Lahabrea",
|
||||||
|
"Lyse",
|
||||||
|
"Merlwyb",
|
||||||
|
"Minfilia",
|
||||||
|
"Nanamo Ul Namo",
|
||||||
|
"Papalymo",
|
||||||
|
"Raubahn",
|
||||||
|
"Ryne",
|
||||||
|
"Tataru",
|
||||||
|
"Thancred",
|
||||||
|
"Themis",
|
||||||
|
"Urianger",
|
||||||
|
"Venat",
|
||||||
|
"Wedge",
|
||||||
|
"Y'shtola",
|
||||||
|
"Yda",
|
||||||
|
"Yugiri",
|
||||||
};
|
};
|
||||||
|
|
||||||
internal IReadOnlyDictionary<uint, IReadOnlyList<Item>> JobMainHands { get; }
|
internal IReadOnlyDictionary<uint, IReadOnlyList<Item>> JobMainHands { get; }
|
||||||
|
@ -68,11 +74,11 @@ internal class AppearanceRepository {
|
||||||
var allMainHands = this.Plugin.DataManager.GetExcelSheet<Item>()!
|
var allMainHands = this.Plugin.DataManager.GetExcelSheet<Item>()!
|
||||||
.Where(row => row.EquipSlotCategory.Value!.MainHand != 0)
|
.Where(row => row.EquipSlotCategory.Value!.MainHand != 0)
|
||||||
// let's not give people ultimate weapons and shit
|
// let's not give people ultimate weapons and shit
|
||||||
.Where(row => !row.IsUnique && !row.IsUntradable)
|
.Where(row => !row.IsUnique)
|
||||||
.ToList();
|
.ToList();
|
||||||
var allOffHands = this.Plugin.DataManager.GetExcelSheet<Item>()!
|
var allOffHands = this.Plugin.DataManager.GetExcelSheet<Item>()!
|
||||||
.Where(row => row.EquipSlotCategory.Value!.OffHand != 0)
|
.Where(row => row.EquipSlotCategory.Value!.OffHand != 0)
|
||||||
.Where(row => !row.IsUnique && !row.IsUntradable)
|
.Where(row => !row.IsUnique)
|
||||||
.ToList();
|
.ToList();
|
||||||
foreach (var job in this.Plugin.DataManager.GetExcelSheet<ClassJob>(ClientLanguage.English)!) {
|
foreach (var job in this.Plugin.DataManager.GetExcelSheet<ClassJob>(ClientLanguage.English)!) {
|
||||||
if (job.RowId == 0) {
|
if (job.RowId == 0) {
|
||||||
|
@ -122,6 +128,7 @@ internal class AppearanceRepository {
|
||||||
|
|
||||||
internal void Reset() {
|
internal void Reset() {
|
||||||
this.Salt = new Random().Next();
|
this.Salt = new Random().Next();
|
||||||
|
this.Cache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RefilterPersonal() {
|
internal void RefilterPersonal() {
|
||||||
|
@ -142,15 +149,22 @@ internal class AppearanceRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetNpcIndex(uint objectId) {
|
private int GetNpcIndex(uint objectId) {
|
||||||
return new Random((int) (objectId + this.Salt)).Next(0, this.Npcs.Count);
|
if (this.Cache.TryGetValue(objectId, out var index)) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
var idx = new Random((int) (objectId + this.Salt)).Next(0, this.Npcs.Count);
|
||||||
|
this.Cache[objectId] = idx;
|
||||||
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetNpcIndexPersonal(uint objectId) {
|
private int GetNpcIndexPersonal(uint objectId) {
|
||||||
return new Random((int) (objectId + this.Salt)).Next(0, this.PersonalNpcs.Count);
|
return new Random((int) (objectId + this.Salt)).Next(0, this.PersonalNpcs.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ENpcBase GetNpc(uint objectId) {
|
internal unsafe ENpcBase GetNpc(uint objectId) {
|
||||||
if (objectId == this.Plugin.ClientState.LocalPlayer?.ObjectId && this.PersonalNpcs.Count > 0) {
|
var player = *(GameObject**) this.Plugin.ObjectTable.Address;
|
||||||
|
if (player != null && objectId == player->ObjectID && this.PersonalNpcs.Count > 0) {
|
||||||
return this.PersonalNpcs[this.GetNpcIndexPersonal(objectId)];
|
return this.PersonalNpcs[this.GetNpcIndexPersonal(objectId)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,15 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using Dalamud.Game;
|
using Dalamud.Game;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Game.Text;
|
using Dalamud.Game.Text;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Group;
|
||||||
using XivCommon.Functions.NamePlates;
|
using XivCommon.Functions.NamePlates;
|
||||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||||
|
|
||||||
|
@ -17,7 +20,7 @@ internal class Obscurer : IDisposable {
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
private Stopwatch UpdateTimer { get; } = new();
|
private Stopwatch UpdateTimer { get; } = new();
|
||||||
private IList<string> Friends { get; set; }
|
private IReadOnlySet<string> Friends { get; set; }
|
||||||
|
|
||||||
internal unsafe Obscurer(Plugin plugin) {
|
internal unsafe Obscurer(Plugin plugin) {
|
||||||
this.Plugin = plugin;
|
this.Plugin = plugin;
|
||||||
|
@ -26,7 +29,7 @@ internal class Obscurer : IDisposable {
|
||||||
|
|
||||||
this.Friends = this.Plugin.Common.Functions.FriendList.List
|
this.Friends = this.Plugin.Common.Functions.FriendList.List
|
||||||
.Select(friend => friend.Name.TextValue)
|
.Select(friend => friend.Name.TextValue)
|
||||||
.ToList();
|
.ToHashSet();
|
||||||
|
|
||||||
this.Plugin.Framework.Update += this.OnFrameworkUpdate;
|
this.Plugin.Framework.Update += this.OnFrameworkUpdate;
|
||||||
this.Plugin.Functions.AtkTextNodeSetText += this.OnAtkTextNodeSetText;
|
this.Plugin.Functions.AtkTextNodeSetText += this.OnAtkTextNodeSetText;
|
||||||
|
@ -63,15 +66,22 @@ internal class Obscurer : IDisposable {
|
||||||
|
|
||||||
this.Friends = this.Plugin.Common.Functions.FriendList.List
|
this.Friends = this.Plugin.Common.Functions.FriendList.List
|
||||||
.Select(friend => friend.Name.TextValue)
|
.Select(friend => friend.Name.TextValue)
|
||||||
.ToList();
|
.ToHashSet();
|
||||||
this.UpdateTimer.Restart();
|
this.UpdateTimer.Restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Regex Coords = new(@"^X: \d+. Y: \d+.(?: Z: \d+.)?$", RegexOptions.Compiled);
|
||||||
|
|
||||||
private void OnAtkTextNodeSetText(IntPtr node, IntPtr textPtr, ref SeString? overwrite) {
|
private void OnAtkTextNodeSetText(IntPtr node, IntPtr textPtr, ref SeString? overwrite) {
|
||||||
// A catch-all for UI text. This is slow, so specialised methods should be preferred.
|
// A catch-all for UI text. This is slow, so specialised methods should be preferred.
|
||||||
|
|
||||||
var text = Util.ReadRawSeString(textPtr);
|
var text = Util.ReadRawSeString(textPtr);
|
||||||
|
|
||||||
|
var tval = text.TextValue;
|
||||||
|
if (string.IsNullOrWhiteSpace(tval) || tval.All(c => !char.IsLetter(c)) || Coords.IsMatch(tval)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var changed = this.ChangeNames(text);
|
var changed = this.ChangeNames(text);
|
||||||
if (changed) {
|
if (changed) {
|
||||||
overwrite = text;
|
overwrite = text;
|
||||||
|
@ -86,31 +96,31 @@ internal class Obscurer : IDisposable {
|
||||||
if (gameObj->ObjectKind != (byte) FFXIVClientStructs.FFXIV.Client.Game.Object.ObjectKind.Pc) {
|
if (gameObj->ObjectKind != (byte) FFXIVClientStructs.FFXIV.Client.Game.Object.ObjectKind.Pc) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameObject = this.Plugin.ObjectTable.CreateObjectReference((IntPtr) gameObj)!;
|
var gameObject = this.Plugin.ObjectTable.CreateObjectReference((IntPtr) gameObj)!;
|
||||||
return gameObject is Character chara && this.ShouldObscureAppearance(chara);
|
return gameObject is Character chara && this.ShouldObscureAppearance(chara);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldObscureAppearance(Character chara) {
|
private unsafe bool ShouldObscureAppearance(Character chara) {
|
||||||
if (!this.Plugin.Config.Enabled) {
|
if (!this.Plugin.Config.Enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = chara.Name.TextValue;
|
var gameChara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*) chara.Address;
|
||||||
var isFriend = this.Friends.Contains(name);
|
var name = Marshal.PtrToStringUTF8((IntPtr) gameChara->GameObject.Name)!;
|
||||||
|
|
||||||
if (this.Plugin.Config.ObscureAppearancesExcludeFriends && isFriend) {
|
if (this.Plugin.Config.ObscureAppearancesExcludeFriends && this.Friends.Contains(name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.Plugin.Config.ObscureAppearancesSelf && chara.ObjectId == this.Plugin.ClientState.LocalPlayer?.ObjectId) {
|
var player = *(GameObject**) this.Plugin.ObjectTable.Address;
|
||||||
return true;
|
if (player != null && player->ObjectID == chara.ObjectId) {
|
||||||
|
return this.Plugin.Config.ObscureAppearancesSelf;
|
||||||
}
|
}
|
||||||
|
|
||||||
var party = this.Plugin.PartyList.Select(member => member.ObjectId).ToArray();
|
var party = this.Plugin.PartyList.Select(member => member.ObjectId);
|
||||||
var inParty = party.Contains(chara.ObjectId);
|
if (party.Contains(chara.ObjectId)) {
|
||||||
if (this.Plugin.Config.ObscureAppearancesParty && inParty) {
|
return this.Plugin.Config.ObscureAppearancesParty;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.Plugin.Config.ObscureAppearancesOthers;
|
return this.Plugin.Config.ObscureAppearancesOthers;
|
||||||
|
@ -120,7 +130,7 @@ internal class Obscurer : IDisposable {
|
||||||
if (!this.ShouldObscureAppearance(gameObj)) {
|
if (!this.ShouldObscureAppearance(gameObj)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var npc = this.Plugin.AppearanceRepository.GetNpc(gameObj->ObjectID);
|
var npc = this.Plugin.AppearanceRepository.GetNpc(gameObj->ObjectID);
|
||||||
|
|
||||||
var customise = (byte*) customiseDataPtr;
|
var customise = (byte*) customiseDataPtr;
|
||||||
|
@ -171,11 +181,11 @@ internal class Obscurer : IDisposable {
|
||||||
if (equipData == null) {
|
if (equipData == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.ShouldObscureAppearance(gameObj)) {
|
if (!this.ShouldObscureAppearance(gameObj)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var chara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*) gameObj;
|
var chara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*) gameObj;
|
||||||
var (mainHand, offHand) = this.Plugin.AppearanceRepository.GetHands(chara->ClassJob, gameObj->ObjectID);
|
var (mainHand, offHand) = this.Plugin.AppearanceRepository.GetHands(chara->ClassJob, gameObj->ObjectID);
|
||||||
|
|
||||||
|
@ -232,7 +242,7 @@ internal class Obscurer : IDisposable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = GetInfo(chara);
|
var info = this.GetInfo(chara);
|
||||||
|
|
||||||
void Change(string name) {
|
void Change(string name) {
|
||||||
this.ChangeName(args.Name, name, info);
|
this.ChangeName(args.Name, name, info);
|
||||||
|
@ -278,10 +288,6 @@ internal class Obscurer : IDisposable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text.ContainsPlayerName(name)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
text.ReplacePlayerName(name, replacement);
|
text.ReplacePlayerName(name, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,26 +303,26 @@ internal class Obscurer : IDisposable {
|
||||||
|
|
||||||
var player = this.Plugin.ClientState.LocalPlayer;
|
var player = this.Plugin.ClientState.LocalPlayer;
|
||||||
|
|
||||||
if (this.Plugin.Config.SelfFull) {
|
if (player != null && this.Plugin.Config.SelfFull) {
|
||||||
var playerName = player?.Name.TextValue;
|
var playerName = player.RawName()!;
|
||||||
if (playerName != null && text.ContainsPlayerName(playerName) && this.Plugin.NameRepository.GetReplacement(playerName, GetInfo(player!)) is { } replacement) {
|
if (this.Plugin.NameRepository.GetReplacement(playerName, this.GetInfo(player!)) is { } replacement) {
|
||||||
text.ReplacePlayerName(playerName, replacement);
|
text.ReplacePlayerName(playerName, replacement);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.Plugin.Config.SelfFirst || this.Plugin.Config.SelfLast) {
|
if (player != null && (this.Plugin.Config.SelfFirst || this.Plugin.Config.SelfLast)) {
|
||||||
var playerName = player?.Name.TextValue;
|
var playerName = player.RawName()!;
|
||||||
if (playerName != null && this.Plugin.NameRepository.GetReplacement(playerName, GetInfo(player!)) is { } replacement) {
|
if (this.Plugin.NameRepository.GetReplacement(playerName, this.GetInfo(player!)) is { } replacement) {
|
||||||
var parts = playerName.Split(' ', 2);
|
var parts = playerName.Split(' ', 2);
|
||||||
var replacementParts = replacement.Split(' ', 2);
|
var replacementParts = replacement.Split(' ', 2);
|
||||||
|
|
||||||
if (this.Plugin.Config.SelfFirst && text.ContainsPlayerName(parts[0])) {
|
if (this.Plugin.Config.SelfFirst) {
|
||||||
text.ReplacePlayerName(parts[0], replacementParts[0]);
|
text.ReplacePlayerName(parts[0], replacementParts[0]);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.Plugin.Config.SelfLast && text.ContainsPlayerName(parts[1])) {
|
if (this.Plugin.Config.SelfLast) {
|
||||||
text.ReplacePlayerName(parts[1], replacementParts[1]);
|
text.ReplacePlayerName(parts[1], replacementParts[1]);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -325,14 +331,18 @@ internal class Obscurer : IDisposable {
|
||||||
|
|
||||||
if (this.Plugin.Config.Party) {
|
if (this.Plugin.Config.Party) {
|
||||||
foreach (var member in this.Plugin.PartyList) {
|
foreach (var member in this.Plugin.PartyList) {
|
||||||
var name = member.Name.TextValue;
|
string name;
|
||||||
|
unsafe {
|
||||||
|
var raw = (PartyMember*) member.Address;
|
||||||
|
name = Marshal.PtrToStringUTF8((IntPtr) raw->Name)!;
|
||||||
|
}
|
||||||
|
|
||||||
var info = ((byte) 0xFF, (byte) 0xFF, member.Sex);
|
var info = ((byte) 0xFF, (byte) 0xFF, member.Sex);
|
||||||
if (member.GameObject is Character chara) {
|
if (member.GameObject is Character chara) {
|
||||||
info = GetInfo(chara);
|
info = this.GetInfo(chara);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (member.ObjectId == player?.ObjectId || !text.ContainsPlayerName(name) || this.Plugin.NameRepository.GetReplacement(name, info) is not { } replacement) {
|
if (member.ObjectId == player?.ObjectId || this.Plugin.NameRepository.GetReplacement(name, info) is not { } replacement) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,17 +363,17 @@ internal class Obscurer : IDisposable {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = chara.Name.TextValue;
|
var name = chara.RawName()!;
|
||||||
if (this.Plugin.Config.ExcludeFriends && this.Friends.Contains(name)) {
|
if (this.Plugin.Config.ExcludeFriends && this.Friends.Contains(name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var info = GetInfo(chara);
|
var info = this.GetInfo(chara);
|
||||||
if (info.race == 0) {
|
if (info.race == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.Plugin.NameRepository.GetReplacement(name, GetInfo(chara)) is not { } replacement) {
|
if (this.Plugin.NameRepository.GetReplacement(name, this.GetInfo(chara)) is not { } replacement) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +392,7 @@ internal class Obscurer : IDisposable {
|
||||||
(byte) npc.Race.Row,
|
(byte) npc.Race.Row,
|
||||||
(byte) ((npc.Tribe.Row - 1) % 2),
|
(byte) ((npc.Tribe.Row - 1) % 2),
|
||||||
npc.Gender
|
npc.Gender
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Dalamud.Game.ClientState.Objects.Types;
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
|
|
||||||
|
@ -8,27 +10,6 @@ namespace NominaOcculta;
|
||||||
internal static class Util {
|
internal static class Util {
|
||||||
internal const string SheetName = "CharaMakeName";
|
internal const string SheetName = "CharaMakeName";
|
||||||
|
|
||||||
internal static bool ContainsPlayerName(this SeString text, string name) {
|
|
||||||
foreach (var payload in text.Payloads) {
|
|
||||||
switch (payload) {
|
|
||||||
case PlayerPayload pp:
|
|
||||||
if (pp.PlayerName.Contains(name)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case ITextProvider prov:
|
|
||||||
if (prov.Text.Contains(name)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ReplacePlayerName(this SeString text, string name, string replacement) {
|
internal static void ReplacePlayerName(this SeString text, string name, string replacement) {
|
||||||
if (string.IsNullOrEmpty(name)) {
|
if (string.IsNullOrEmpty(name)) {
|
||||||
return;
|
return;
|
||||||
|
@ -52,6 +33,11 @@ internal static class Util {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static unsafe string? RawName(this GameObject obj) {
|
||||||
|
var gameObj = (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*) obj.Address;
|
||||||
|
return Marshal.PtrToStringUTF8((IntPtr) gameObj->Name);
|
||||||
|
}
|
||||||
|
|
||||||
internal static byte[] Terminate(this byte[] bs) {
|
internal static byte[] Terminate(this byte[] bs) {
|
||||||
var terminated = new byte[bs.Length + 1];
|
var terminated = new byte[bs.Length + 1];
|
||||||
Array.Copy(bs, terminated, bs.Length);
|
Array.Copy(bs, terminated, bs.Length);
|
||||||
|
|
Loading…
Reference in New Issue