fix(nameplates): prevent crash

This commit is contained in:
Anna 2021-06-22 16:24:01 -04:00
parent c5712f8acf
commit 646a49bc33
2 changed files with 35 additions and 4 deletions

View File

@ -1,4 +1,5 @@
using Dalamud.Game.Text.SeStringHandling;
using System;
using Dalamud.Game.Text.SeStringHandling;
using FFXIVClientStructs.FFXIV.Client.Graphics;
namespace XivCommon.Functions.NamePlates {
@ -29,8 +30,23 @@ namespace XivCommon.Functions.NamePlates {
/// <summary>
/// The level string for name plates that use it. Set to the empty string to disable.
/// </summary>
///
public SeString Level { get; set; } = null!;
/// <summary>
/// <para>
/// The letter that appears after enemy names, such as A, B, etc.
/// </para>
/// <para>
/// <b>Setting this property will always cause a memory leak.</b>
/// </para>
/// </summary>
public SeString EnemyLetter {
get;
[Obsolete("Setting this property will always cause a memory leak.")]
set;
} = null!;
/// <summary>
/// The icon to be shown on this name plate. Use <see cref="uint.MaxValue"/> for no icon.
/// </summary>

View File

@ -77,7 +77,8 @@ namespace XivCommon.Functions.NamePlates {
private const int NameIndex = 0;
private const int TitleIndex = 50;
private const int FreeCompanyIndex = 100;
private const int LevelIndex = 150;
private const int EnemyLetterIndex = 150;
private const int LevelIndex = 200;
private unsafe IntPtr NamePlateUpdateDetour(AddonNamePlate* addon, NumberArrayData** numberData, StringArrayData** stringData) {
try {
@ -142,11 +143,17 @@ namespace XivCommon.Functions.NamePlates {
var levelRaw = strings->StringArray[LevelIndex + i];
var level = Util.ReadSeString((IntPtr) levelRaw, this.SeStringManager);
var letterRaw = strings->StringArray[EnemyLetterIndex + i];
var letter = Util.ReadSeString((IntPtr) letterRaw, this.SeStringManager);
var args = new NamePlateUpdateEventArgs((uint) info.ActorID) {
Name = new SeString(name.Payloads),
FreeCompany = new SeString(fc.Payloads),
Title = new SeString(title.Payloads),
Level = new SeString(level.Payloads),
#pragma warning disable 0618
EnemyLetter = new SeString(letter.Payloads),
#pragma warning restore 0618
Colour = nameColour,
Icon = (uint) icon,
Type = (PlateType) plateType,
@ -159,7 +166,7 @@ namespace XivCommon.Functions.NamePlates {
Logger.LogError(ex, "Exception in name plate update event");
}
void Replace(byte[] bytes, int i) {
void Replace(byte[] bytes, int i, bool free = true) {
// allocate new memory with the game for the new string
var mem = this.Functions.UiAlloc.Alloc((ulong) bytes.Length + 1);
// copy the new string over to the game's memory
@ -171,7 +178,9 @@ namespace XivCommon.Functions.NamePlates {
var old = strings->StringArray[i];
strings->StringArray[i] = (byte*) mem;
// free the old pointer
this.Functions.UiAlloc.Free((IntPtr) old);
if (free && old != null) {
this.Functions.UiAlloc.Free((IntPtr) old);
}
}
if (name != args.Name) {
@ -190,6 +199,12 @@ namespace XivCommon.Functions.NamePlates {
Replace(args.Level.Encode(), LevelIndex + i);
}
if (letter != args.EnemyLetter) {
// FIXME: sometimes the pointer here in the game is garbage, so freeing is a heap corruption
// figure out how to free this properly
Replace(args.EnemyLetter.Encode(), EnemyLetterIndex + i, false);
}
if (icon != args.Icon) {
numbers->SetValue(numbersIndex + IconIndex, (int) args.Icon);
}