From d14f3fcd2c21f6fe2787cfbcb8cb5634df2229b0 Mon Sep 17 00:00:00 2001 From: Anna Clemens Date: Sun, 27 Dec 2020 12:13:57 -0500 Subject: [PATCH] refactor: update to sdk and use DalamudPackager --- .gitignore | 1 + GoodMemory/ActionType.cs | 8 +-- GoodMemory/DalamudPackager.targets | 10 +++ GoodMemory/GameFunctions.cs | 45 +++++++------ GoodMemory/GoodMemory.csproj | 89 ++++++++------------------ GoodMemory/GoodMemory.json | 10 --- GoodMemory/GoodMemory.yaml | 8 +++ GoodMemory/Plugin.cs | 91 +++++++++++++-------------- GoodMemory/Properties/AssemblyInfo.cs | 38 ----------- 9 files changed, 117 insertions(+), 183 deletions(-) create mode 100644 GoodMemory/DalamudPackager.targets delete mode 100644 GoodMemory/GoodMemory.json create mode 100644 GoodMemory/GoodMemory.yaml delete mode 100644 GoodMemory/Properties/AssemblyInfo.cs diff --git a/.gitignore b/.gitignore index 1ee5385..40dcb4c 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ +.idea/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ diff --git a/GoodMemory/ActionType.cs b/GoodMemory/ActionType.cs index cb653d0..bff2855 100644 --- a/GoodMemory/ActionType.cs +++ b/GoodMemory/ActionType.cs @@ -4,15 +4,15 @@ using System.Linq; namespace GoodMemory { public static class ActionTypeExt { - private static readonly ActionType[] VALID = (ActionType[])Enum.GetValues(typeof(ActionType)); + private static readonly ActionType[] Valid = (ActionType[])Enum.GetValues(typeof(ActionType)); - public static bool IsValidAction(ItemAction action) { + public static bool IsValidAction(ItemAction? action) { if (action == null || action.RowId == 0) { return false; } - ActionType type = (ActionType)action.Type; - return VALID.Contains(type); + var type = (ActionType)action.Type; + return Valid.Contains(type); } } diff --git a/GoodMemory/DalamudPackager.targets b/GoodMemory/DalamudPackager.targets new file mode 100644 index 0000000..41f4094 --- /dev/null +++ b/GoodMemory/DalamudPackager.targets @@ -0,0 +1,10 @@ + + + + + diff --git a/GoodMemory/GameFunctions.cs b/GoodMemory/GameFunctions.cs index 4581be4..dfd409a 100644 --- a/GoodMemory/GameFunctions.cs +++ b/GoodMemory/GameFunctions.cs @@ -4,58 +4,57 @@ using System.Runtime.InteropServices; namespace GoodMemory { public class GameFunctions { - private readonly Plugin plugin; + private Plugin Plugin { get; } private delegate byte HasItemActionUnlockedDelegate(long itemActionId); - private readonly HasItemActionUnlockedDelegate hasItemActionUnlocked; + + private readonly HasItemActionUnlockedDelegate _hasItemActionUnlocked; private delegate byte HasCardDelegate(IntPtr localPlayer, ushort cardId); - private readonly HasCardDelegate hasCard; - private readonly IntPtr cardStaticAddr; + private readonly HasCardDelegate _hasCard; + + private readonly IntPtr _cardStaticAddr; public GameFunctions(Plugin plugin) { - this.plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "Plugin cannot be null"); + this.Plugin = plugin ?? throw new ArgumentNullException(nameof(plugin), "Plugin cannot be null"); - IntPtr hasIAUnlockedPtr = plugin.Interface.TargetModuleScanner.ScanText("48 83 EC 28 E8 ?? ?? ?? ?? 48 85 C0 0F 84 ?? ?? ?? ??"); - IntPtr hasCardPtr = plugin.Interface.TargetModuleScanner.ScanText("40 53 48 83 EC 20 48 8B D9 66 85 D2 74 ??"); - this.cardStaticAddr = plugin.Interface.TargetModuleScanner.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 84 C0 74 ?? 48 8B 53 ?? 48 8D 4B ?? 48 83 C2 0C 48 8D 14 ?? E8 ?? ?? ?? ?? 40 FE C7 40 3A FD 72 ?? 48 8B 5C 24 ??"); + var hasIaUnlockedPtr = plugin.Interface.TargetModuleScanner.ScanText("48 83 EC 28 E8 ?? ?? ?? ?? 48 85 C0 0F 84 ?? ?? ?? ??"); + var hasCardPtr = plugin.Interface.TargetModuleScanner.ScanText("40 53 48 83 EC 20 48 8B D9 66 85 D2 74 ??"); + this._cardStaticAddr = plugin.Interface.TargetModuleScanner.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 84 C0 74 ?? 48 8B 53 ?? 48 8D 4B ?? 48 83 C2 0C 48 8D 14 ?? E8 ?? ?? ?? ?? 40 FE C7 40 3A FD 72 ?? 48 8B 5C 24 ??"); - if (hasIAUnlockedPtr == IntPtr.Zero || hasCardPtr == IntPtr.Zero || this.cardStaticAddr == IntPtr.Zero) { + if (hasIaUnlockedPtr == IntPtr.Zero || hasCardPtr == IntPtr.Zero || this._cardStaticAddr == IntPtr.Zero) { throw new ApplicationException("Could not get pointers for game functions"); } - this.hasItemActionUnlocked = Marshal.GetDelegateForFunctionPointer(hasIAUnlockedPtr); - this.hasCard = Marshal.GetDelegateForFunctionPointer(hasCardPtr); + this._hasItemActionUnlocked = Marshal.GetDelegateForFunctionPointer(hasIaUnlockedPtr); + this._hasCard = Marshal.GetDelegateForFunctionPointer(hasCardPtr); } public bool HasAcquired(Item item) { - ItemAction action = item.ItemAction.Value; + var action = item.ItemAction.Value; if (action == null) { return false; } - ActionType type = (ActionType)action.Type; + var type = (ActionType)action.Type; - if (type == ActionType.Cards) { - uint cardId = item.AdditionalData; - TripleTriadCard card = this.plugin.Interface.Data.GetExcelSheet().GetRow(cardId); - if (card == null) { - return false; - } - return this.HasCard((ushort)card.RowId); + if (type != ActionType.Cards) { + return this.HasItemActionUnlocked(action.RowId); } - return this.HasItemActionUnlocked(action.RowId); + var cardId = item.AdditionalData; + var card = this.Plugin.Interface.Data.GetExcelSheet().GetRow(cardId); + return card != null && this.HasCard((ushort)card.RowId); } private bool HasItemActionUnlocked(long itemActionId) { - return this.hasItemActionUnlocked(itemActionId) == 1; + return this._hasItemActionUnlocked(itemActionId) == 1; } private bool HasCard(ushort cardId) { - return this.hasCard(this.cardStaticAddr, cardId) == 1; + return this._hasCard(this._cardStaticAddr, cardId) == 1; } } } diff --git a/GoodMemory/GoodMemory.csproj b/GoodMemory/GoodMemory.csproj index 0bb4bc0..7c05cd1 100644 --- a/GoodMemory/GoodMemory.csproj +++ b/GoodMemory/GoodMemory.csproj @@ -1,64 +1,29 @@  - - - - Debug - AnyCPU - {2B53DAAE-5F20-4EAF-8BC5-97FCE68C1738} - Library - Properties - GoodMemory - GoodMemory - v4.8 - 512 - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - - - - $(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll - - - $(AppData)\XIVLauncher\addon\Hooks\Lumina.dll - - - $(AppData)\XIVLauncher\addon\Hooks\Lumina.Excel.dll - - - - - - - - - - - - - - - - - - - - + + + 8 + enable + 1.0.4 + 1.0.4 + net48 + true + x64 + + + + $(AppData)\XIVLauncher\addon\Hooks\Dalamud.dll + false + + + $(AppData)\XIVLauncher\addon\Hooks\Lumina.dll + false + + + $(AppData)\XIVLauncher\addon\Hooks\Lumina.Excel.dll + false + + + + + \ No newline at end of file diff --git a/GoodMemory/GoodMemory.json b/GoodMemory/GoodMemory.json deleted file mode 100644 index c46e447..0000000 --- a/GoodMemory/GoodMemory.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Author": "ascclemens", - "Name": "Good Memory", - "Description": "Adds an indicator in item tooltips to show whether you have acquired that item.", - "InternalName": "GoodMemory", - "AssemblyVersion": "1.0.4", - "RepoUrl": "https://git.sr.ht/~jkcclemens/GoodMemory", - "ApplicableVersion": "any", - "DalamudApiLevel": 2 -} diff --git a/GoodMemory/GoodMemory.yaml b/GoodMemory/GoodMemory.yaml new file mode 100644 index 0000000..719e67e --- /dev/null +++ b/GoodMemory/GoodMemory.yaml @@ -0,0 +1,8 @@ +author: ascclemens +name: GoodMemory +description: |- + Adds an indicator in item tooltips to show whether you have acquired that item. + + This indicator is in the item's description near the bottom and only appears for + items that are unlockable, such as orchestrion rolls, minions, etc. +repo_url: https://git.sr.ht/~jkcclemens/GoodMemory diff --git a/GoodMemory/Plugin.cs b/GoodMemory/Plugin.cs index 4774ccf..c8b5e71 100644 --- a/GoodMemory/Plugin.cs +++ b/GoodMemory/Plugin.cs @@ -9,14 +9,14 @@ using System.Text; namespace GoodMemory { public class Plugin : IDalamudPlugin { - private bool disposedValue; + private bool _disposedValue; public string Name => "Good Memory"; - public DalamudPluginInterface Interface { get; private set; } - private GameFunctions Functions { get; set; } - private readonly IntPtr alloc = Marshal.AllocHGlobal(4096); - private Hook tooltipHook; + 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); @@ -27,46 +27,48 @@ namespace GoodMemory { } protected virtual void Dispose(bool disposing) { - if (!this.disposedValue) { - if (disposing) { - this.tooltipHook?.Dispose(); - Marshal.FreeHGlobal(this.alloc); - } - - this.disposedValue = true; + if (this._disposedValue) { + return; } + + if (disposing) { + this._tooltipHook?.Dispose(); + Marshal.FreeHGlobal(this._alloc); + } + + this._disposedValue = true; } public void Dispose() { // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method - Dispose(disposing: true); + Dispose(true); GC.SuppressFinalize(this); } private void SetUpHook() { - IntPtr 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 ??"); + 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 = new Hook(tooltipPtr, new TooltipDelegate(this.OnTooltip)); } - this.tooltipHook.Enable(); + this._tooltipHook.Enable(); } - private unsafe void TooltipLogic(IntPtr a1, uint** a2, byte*** a3) { + 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 - uint* v3 = *(a2 + 4); - uint v9 = *(v3 + 4); + var v3 = *(a2 + 4); + var v9 = *(v3 + 4); if ((v9 & 2) == 0) { return; } - ulong itemId = this.Interface.Framework.Gui.HoveredItem; + var itemId = this.Interface.Framework.Gui.HoveredItem; if (itemId > 2_000_000) { return; } @@ -75,19 +77,19 @@ namespace GoodMemory { itemId -= 1_000_000; } - Item item = this.Interface.Data.GetExcelSheet().GetRow((uint)itemId); + var item = this.Interface.Data.GetExcelSheet().GetRow((uint)itemId); if (item == null) { return; } // get the pointer to the text - byte** startPtr = *(a3 + 4) + 13; + var startPtr = *(a3 + 4) + 13; // get the text pointer - byte* start = *startPtr; + var start = *startPtr; // work around function being called twice - if (start == (byte*)this.alloc) { + if (start == (byte*)this._alloc) { return; } @@ -95,7 +97,7 @@ namespace GoodMemory { // Faded Copies if (item.FilterGroup == 12 && item.ItemUICategory.Value?.RowId == 94 && item.LevelItem.Value?.RowId == 1) { - Item[] recipeResults = this.Interface.Data.GetExcelSheet() + var recipeResults = this.Interface.Data.GetExcelSheet() .Where(recipe => recipe.UnkStruct5.Any(ritem => ritem.ItemIngredient == item.RowId)) .Select(recipe => recipe.ItemResult.Value) .Where(result => result != null) @@ -103,16 +105,16 @@ namespace GoodMemory { overwrite = ReadString(start); - foreach (Item result in recipeResults) { - ItemAction resultAction = result.ItemAction?.Value; + foreach (var result in recipeResults) { + var resultAction = result.ItemAction?.Value; if (!ActionTypeExt.IsValidAction(resultAction)) { continue; } Debug.Assert(resultAction != null, nameof(resultAction) + " != null"); - uint orchId = resultAction.Data[0]; - Orchestrion orch = this.Interface.Data.GetExcelSheet().GetRow(orchId); + uint orchId = resultAction!.Data[0]; + var orch = this.Interface.Data.GetExcelSheet().GetRow(orchId); if (orch == null) { continue; } @@ -120,7 +122,7 @@ namespace GoodMemory { this.AppendIfAcquired(ref overwrite, result, orch.Name); } } else { - ItemAction action = item.ItemAction?.Value; + var action = item.ItemAction?.Value; if (!ActionTypeExt.IsValidAction(action)) { return; @@ -134,23 +136,23 @@ namespace GoodMemory { } // write our replacement text into our own managed memory (4096 bytes) - WriteString((byte*)this.alloc, overwrite, true); + WriteString((byte*)this._alloc, overwrite, true); // overwrite the original pointer with our own - *startPtr = (byte*)this.alloc; + *startPtr = (byte*)this._alloc; } private unsafe IntPtr OnTooltip(IntPtr a1, uint** a2, byte*** a3) { try { - this.TooltipLogic(a1, a2, a3); + 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); + return this._tooltipHook!.Original(a1, a2, a3); } - private void AppendIfAcquired(ref string txt, Item item, string name = null) { + private void AppendIfAcquired(ref string txt, Item item, string? name = null) { string yes; string no; string acquired; @@ -158,7 +160,6 @@ namespace GoodMemory { string parenL; string parenR; switch (this.Interface.ClientState.ClientLanguage) { - case Dalamud.ClientLanguage.English: default: acquired = "Acquired"; colon = ": "; @@ -193,18 +194,16 @@ namespace GoodMemory { break; } - string has = this.Functions.HasAcquired(item) ? yes : no; - if (name != null) { - txt = $"{txt}\n{acquired}{parenL}{name}{parenR}{colon}{has}"; - } else { - txt = $"{txt}\n{acquired}{colon}{has}"; - } + 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 unsafe static string ReadString(byte* ptr) { - int offset = 0; + var offset = 0; while (true) { - byte b = *(ptr + offset); + var b = *(ptr + offset); if (b == 0) { break; } @@ -216,8 +215,8 @@ namespace GoodMemory { } private unsafe static void WriteString(byte* dst, string s, bool finalise = false) { - byte[] bytes = Encoding.UTF8.GetBytes(s); - for (int i = 0; i < bytes.Length; i++) { + var bytes = Encoding.UTF8.GetBytes(s); + for (var i = 0; i < bytes.Length; i++) { *(dst + i) = bytes[i]; } diff --git a/GoodMemory/Properties/AssemblyInfo.cs b/GoodMemory/Properties/AssemblyInfo.cs deleted file mode 100644 index 9efa092..0000000 --- a/GoodMemory/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Resources; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("GoodMemory")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("GoodMemory")] -[assembly: AssemblyCopyright("Copyright © 2020")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("2b53daae-5f20-4eaf-8bc5-97fce68c1738")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.4")] -[assembly: AssemblyFileVersion("1.0.4")] -[assembly: NeutralResourcesLanguage("en-GB")]