diff --git a/GoodMemory/FodyWeavers.xml b/GoodMemory/FodyWeavers.xml
new file mode 100755
index 0000000..2dfb1f4
--- /dev/null
+++ b/GoodMemory/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/GoodMemory/GoodMemory.csproj b/GoodMemory/GoodMemory.csproj
index a16aaa1..9e307cb 100755
--- a/GoodMemory/GoodMemory.csproj
+++ b/GoodMemory/GoodMemory.csproj
@@ -23,5 +23,8 @@
+
+
+
diff --git a/GoodMemory/Plugin.cs b/GoodMemory/Plugin.cs
index c8da990..9e39f07 100644
--- a/GoodMemory/Plugin.cs
+++ b/GoodMemory/Plugin.cs
@@ -1,74 +1,38 @@
-using Dalamud.Hooking;
-using Dalamud.Plugin;
+using Dalamud.Plugin;
using Lumina.Excel.GeneratedSheets;
using System;
using System.Diagnostics;
using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
+using Dalamud.Game.Text.SeStringHandling;
+using Dalamud.Game.Text.SeStringHandling.Payloads;
+using XivCommon;
+using XivCommon.Functions.Tooltips;
namespace GoodMemory {
public class Plugin : IDalamudPlugin {
- private bool _disposedValue;
-
public string Name => "Good Memory";
public DalamudPluginInterface Interface { get; private set; } = null!;
private GameFunctions Functions { get; set; } = null!;
- private readonly IntPtr _alloc = Marshal.AllocHGlobal(4096);
- private Hook? _tooltipHook;
-
- private unsafe delegate IntPtr TooltipDelegate(IntPtr a1, uint** a2, byte*** a3);
+ private XivCommonBase Common { get; set; } = null!;
public void Initialize(DalamudPluginInterface pluginInterface) {
this.Interface = pluginInterface ?? throw new ArgumentNullException(nameof(pluginInterface), "DalamudPluginInterface cannot be null");
this.Functions = new GameFunctions(this);
- this.SetUpHook();
- }
-
- protected virtual void Dispose(bool disposing) {
- if (this._disposedValue) {
- return;
- }
-
- if (disposing) {
- this._tooltipHook?.Dispose();
- Marshal.FreeHGlobal(this._alloc);
- }
-
- this._disposedValue = true;
+ this.Common = new XivCommonBase(pluginInterface, Hooks.Tooltips);
+ this.Common.Functions.Tooltips.OnItemTooltip += this.OnItemTooltip;
}
public void Dispose() {
- // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
- this.Dispose(true);
- GC.SuppressFinalize(this);
+ this.Common.Functions.Tooltips.OnItemTooltip -= this.OnItemTooltip;
+ this.Common.Dispose();
}
- private void SetUpHook() {
- var tooltipPtr = this.Interface.TargetModuleScanner.ScanText("48 89 5C 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 50 48 8B 42 ??");
- if (tooltipPtr == IntPtr.Zero) {
- throw new ApplicationException("Could not set up tooltip hook because of null pointer");
- }
-
- unsafe {
- this._tooltipHook = new Hook(tooltipPtr, new TooltipDelegate(this.OnTooltip));
- }
-
- this._tooltipHook.Enable();
- }
-
- private unsafe void TooltipLogic(uint** a2, byte*** a3) {
- // this can be replaced with a mid-func hook when reloaded hooks is in dalamud
- // but for now, do the same logic the func does and replace the text after
- var v3 = *(a2 + 4);
- var v9 = *(v3 + 4);
-
- if ((v9 & 2) == 0) {
+ private void OnItemTooltip(ItemTooltip tooltip, ulong itemId) {
+ if (!tooltip.Fields.HasFlag(ItemTooltipFields.Description)) {
return;
}
- var itemId = this.Interface.Framework.Gui.HoveredItem;
if (itemId > 2_000_000) {
return;
}
@@ -78,22 +42,11 @@ namespace GoodMemory {
}
var item = this.Interface.Data.GetExcelSheet- ().GetRow((uint) itemId);
-
if (item == null) {
return;
}
- // get the pointer to the text
- var startPtr = *(a3 + 4) + 13;
- // get the text pointer
- var start = *startPtr;
-
- // work around function being called twice
- if (start == (byte*) this._alloc) {
- return;
- }
-
- string overwrite;
+ var description = tooltip[ItemTooltipString.Description];
// Faded Copies
if (item.FilterGroup == 12 && item.ItemUICategory.Value?.RowId == 94 && item.LevelItem.Value?.RowId == 1) {
@@ -103,8 +56,6 @@ namespace GoodMemory {
.Where(result => result != null)
.ToArray();
- overwrite = ReadString(start);
-
foreach (var result in recipeResults) {
var resultAction = result.ItemAction?.Value;
if (!ActionTypeExt.IsValidAction(resultAction)) {
@@ -119,7 +70,7 @@ namespace GoodMemory {
continue;
}
- this.AppendIfAcquired(ref overwrite, result, orch.Name);
+ this.AppendIfAcquired(description, result, orch.Name);
}
} else {
var action = item.ItemAction?.Value;
@@ -128,31 +79,14 @@ namespace GoodMemory {
return;
}
- // get the text
- overwrite = ReadString(start);
-
// generate our replacement text
- this.AppendIfAcquired(ref overwrite, item);
+ this.AppendIfAcquired(description, item);
}
- // write our replacement text into our own managed memory (4096 bytes)
- WriteString((byte*) this._alloc, overwrite, true);
-
- // overwrite the original pointer with our own
- *startPtr = (byte*) this._alloc;
+ tooltip[ItemTooltipString.Description] = description;
}
- private unsafe IntPtr OnTooltip(IntPtr a1, uint** a2, byte*** a3) {
- try {
- this.TooltipLogic(a2, a3);
- } catch (Exception ex) {
- PluginLog.Error($"Could not modify tooltip:\n{ex.Message}\n{ex.StackTrace}");
- }
-
- return this._tooltipHook!.Original(a1, a2, a3);
- }
-
- private void AppendIfAcquired(ref string txt, Item item, string? name = null) {
+ private void AppendIfAcquired(SeString txt, Item item, string? name = null) {
string yes;
string no;
string acquired;
@@ -195,34 +129,10 @@ namespace GoodMemory {
}
var has = this.Functions.HasAcquired(item) ? yes : no;
- txt = name == null
- ? $"{txt}\n{acquired}{colon}{has}"
- : $"{txt}\n{acquired}{parenL}{name}{parenR}{colon}{has}";
- }
-
- private static unsafe string ReadString(byte* ptr) {
- var offset = 0;
- while (true) {
- var b = *(ptr + offset);
- if (b == 0) {
- break;
- }
-
- offset += 1;
- }
-
- return Encoding.UTF8.GetString(ptr, offset);
- }
-
- private static unsafe void WriteString(byte* dst, string s, bool finalise = false) {
- var bytes = Encoding.UTF8.GetBytes(s);
- for (var i = 0; i < bytes.Length; i++) {
- *(dst + i) = bytes[i];
- }
-
- if (finalise) {
- *(dst + bytes.Length) = 0;
- }
+ var text = name == null
+ ? $"\n{acquired}{colon}{has}"
+ : $"\n{acquired}{parenL}{name}{parenR}{colon}{has}";
+ txt.Payloads.Add(new TextPayload(text));
}
}
}