feat: cope with missing sigs without throwing
This commit is contained in:
parent
02d2e3b042
commit
56c89c333d
|
@ -10,6 +10,10 @@ namespace XivCommon.Functions {
|
|||
/// The class containing BattleTalk functionality
|
||||
/// </summary>
|
||||
public class BattleTalk : IDisposable {
|
||||
private static class Signatures {
|
||||
internal const string AddBattleTalk = "48 89 5C 24 ?? 57 48 83 EC 50 48 8B 01 49 8B D8 0F 29 74 24 ?? 48 8B FA 0F 28 F3 FF 50 40 C7 44 24 ?? ?? ?? ?? ??";
|
||||
}
|
||||
|
||||
private GameFunctions Functions { get; }
|
||||
private SeStringManager SeStringManager { get; }
|
||||
private bool HookEnabled { get; }
|
||||
|
@ -31,7 +35,7 @@ namespace XivCommon.Functions {
|
|||
|
||||
private delegate byte AddBattleTalkDelegate(IntPtr uiModule, IntPtr sender, IntPtr message, float duration, byte style);
|
||||
|
||||
private AddBattleTalkDelegate AddBattleTalk { get; }
|
||||
private AddBattleTalkDelegate? AddBattleTalk { get; }
|
||||
private Hook<AddBattleTalkDelegate>? AddBattleTalkHook { get; }
|
||||
|
||||
internal BattleTalk(GameFunctions functions, SigScanner scanner, SeStringManager seStringManager, bool hook) {
|
||||
|
@ -39,15 +43,14 @@ namespace XivCommon.Functions {
|
|||
this.SeStringManager = seStringManager;
|
||||
this.HookEnabled = hook;
|
||||
|
||||
var addBattleTalkPtr = scanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 50 48 8B 01 49 8B D8 0F 29 74 24 ?? 48 8B FA 0F 28 F3 FF 50 40 C7 44 24 ?? ?? ?? ?? ??");
|
||||
this.AddBattleTalk = Marshal.GetDelegateForFunctionPointer<AddBattleTalkDelegate>(addBattleTalkPtr);
|
||||
if (scanner.ScanTextSafe(Signatures.AddBattleTalk, out var addBattleTalkPtr, "battle talk")) {
|
||||
this.AddBattleTalk = Marshal.GetDelegateForFunctionPointer<AddBattleTalkDelegate>(addBattleTalkPtr);
|
||||
|
||||
if (!this.HookEnabled) {
|
||||
return;
|
||||
if (this.HookEnabled) {
|
||||
this.AddBattleTalkHook = new Hook<AddBattleTalkDelegate>(addBattleTalkPtr, new AddBattleTalkDelegate(this.AddBattleTalkDetour));
|
||||
this.AddBattleTalkHook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
this.AddBattleTalkHook = new Hook<AddBattleTalkDelegate>(addBattleTalkPtr, new AddBattleTalkDelegate(this.AddBattleTalkDetour));
|
||||
this.AddBattleTalkHook.Enable();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -108,6 +111,7 @@ namespace XivCommon.Functions {
|
|||
/// <param name="message">The message to show in the window</param>
|
||||
/// <param name="options">Optional options for the window</param>
|
||||
/// <exception cref="ArgumentException">If sender or message are empty</exception>
|
||||
/// <exception cref="InvalidOperationException">If the signature for this function could not be found</exception>
|
||||
public void Show(SeString sender, SeString message, BattleTalkOptions? options = null) {
|
||||
this.Show(sender.Encode(), message.Encode(), options);
|
||||
}
|
||||
|
@ -121,6 +125,10 @@ namespace XivCommon.Functions {
|
|||
throw new ArgumentException("message cannot be empty", nameof(message));
|
||||
}
|
||||
|
||||
if (this.AddBattleTalk == null) {
|
||||
throw new InvalidOperationException("Signature for battle talk could not be found");
|
||||
}
|
||||
|
||||
options ??= new BattleTalkOptions();
|
||||
|
||||
var uiModule = this.Functions.GetUiModule();
|
||||
|
|
|
@ -9,24 +9,34 @@ namespace XivCommon.Functions {
|
|||
/// A class containing chat functionality
|
||||
/// </summary>
|
||||
public class Chat {
|
||||
private static class Signatures {
|
||||
internal const string SendChat = "48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9";
|
||||
}
|
||||
|
||||
private GameFunctions Functions { get; }
|
||||
|
||||
private delegate void ProcessChatBoxDelegate(IntPtr uiModule, IntPtr message, IntPtr unused, byte a4);
|
||||
|
||||
private ProcessChatBoxDelegate ProcessChatBox { get; }
|
||||
private ProcessChatBoxDelegate? ProcessChatBox { get; }
|
||||
|
||||
internal Chat(GameFunctions functions, SigScanner scanner) {
|
||||
this.Functions = functions;
|
||||
|
||||
var processChatBoxPtr = scanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9");
|
||||
this.ProcessChatBox = Marshal.GetDelegateForFunctionPointer<ProcessChatBoxDelegate>(processChatBoxPtr);
|
||||
if (scanner.ScanTextSafe(Signatures.SendChat, out var processChatBoxPtr, "chat sending")) {
|
||||
this.ProcessChatBox = Marshal.GetDelegateForFunctionPointer<ProcessChatBoxDelegate>(processChatBoxPtr);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a given message to the chat box. <b>This can send chat to the server.</b>
|
||||
/// </summary>
|
||||
/// <param name="message">Message to send</param>
|
||||
/// <exception cref="InvalidOperationException">If the signature for this function could not be found</exception>
|
||||
public void SendMessage(string message) {
|
||||
if (this.ProcessChatBox == null) {
|
||||
throw new InvalidOperationException("Could not find signature for chat sending");
|
||||
}
|
||||
|
||||
var uiModule = this.Functions.GetUiModule();
|
||||
|
||||
using var payload = new ChatPayload(message);
|
||||
|
|
|
@ -11,6 +11,11 @@ namespace XivCommon.Functions {
|
|||
/// Class containing chat bubble events and functions
|
||||
/// </summary>
|
||||
public class ChatBubbles : IDisposable {
|
||||
private static class Signatures {
|
||||
internal const string ChatBubbleOpen = "E8 ?? ?? ?? ?? 80 BF ?? ?? ?? ?? ?? C7 07 ?? ?? ?? ??";
|
||||
internal const string ChatBubbleUpdate = "48 85 D2 0F 84 ?? ?? ?? ?? 48 89 5C 24 ?? 57 48 83 EC 20 8B 41 0C";
|
||||
}
|
||||
|
||||
private Dalamud.Dalamud Dalamud { get; }
|
||||
private SeStringManager SeStringManager { get; }
|
||||
|
||||
|
@ -60,16 +65,18 @@ namespace XivCommon.Functions {
|
|||
return;
|
||||
}
|
||||
|
||||
var openPtr = scanner.ScanText("E8 ?? ?? ?? ?? 80 BF ?? ?? ?? ?? ?? C7 07 ?? ?? ?? ??");
|
||||
this.OpenChatBubbleHook = new Hook<OpenChatBubbleDelegate>(openPtr, new OpenChatBubbleDelegate(this.OpenChatBubbleDetour));
|
||||
this.OpenChatBubbleHook.Enable();
|
||||
|
||||
var updatePtr = scanner.ScanText("48 85 D2 0F 84 ?? ?? ?? ?? 48 89 5C 24 ?? 57 48 83 EC 20 8B 41 0C");
|
||||
unsafe {
|
||||
this.UpdateChatBubbleHook = new Hook<UpdateChatBubbleDelegate>(updatePtr + 9, new UpdateChatBubbleDelegate(this.UpdateChatBubbleDetour));
|
||||
if (scanner.ScanTextSafe(Signatures.ChatBubbleOpen, out var openPtr, "chat bubbles open")) {
|
||||
this.OpenChatBubbleHook = new Hook<OpenChatBubbleDelegate>(openPtr, new OpenChatBubbleDelegate(this.OpenChatBubbleDetour));
|
||||
this.OpenChatBubbleHook.Enable();
|
||||
}
|
||||
|
||||
this.UpdateChatBubbleHook.Enable();
|
||||
if (scanner.ScanTextSafe(Signatures.ChatBubbleUpdate, out var updatePtr, "chat bubbles update")) {
|
||||
unsafe {
|
||||
this.UpdateChatBubbleHook = new Hook<UpdateChatBubbleDelegate>(updatePtr + 9, new UpdateChatBubbleDelegate(this.UpdateChatBubbleDetour));
|
||||
}
|
||||
|
||||
this.UpdateChatBubbleHook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
@ -9,20 +9,25 @@ namespace XivCommon.Functions {
|
|||
/// Class containing examine functions
|
||||
/// </summary>
|
||||
public class Examine {
|
||||
private static class Signatures {
|
||||
internal const string RequestCharacterInfo = "48 89 5C 24 ?? 57 48 83 EC 40 BA ?? ?? ?? ?? 48 8B D9 E8 ?? ?? ?? ?? 48 8B F8 48 85 C0 74 16";
|
||||
}
|
||||
|
||||
private GameFunctions Functions { get; }
|
||||
|
||||
private delegate IntPtr GetAgentModuleDelegate(IntPtr basePtr);
|
||||
|
||||
private delegate long RequestCharInfoDelegate(IntPtr ptr);
|
||||
|
||||
private RequestCharInfoDelegate RequestCharacterInfo { get; }
|
||||
private RequestCharInfoDelegate? RequestCharacterInfo { get; }
|
||||
|
||||
internal Examine(GameFunctions functions, SigScanner scanner) {
|
||||
this.Functions = functions;
|
||||
|
||||
// got this by checking what accesses rciData below
|
||||
var rciPtr = scanner.ScanText("48 89 5C 24 ?? 57 48 83 EC 40 BA ?? ?? ?? ?? 48 8B D9 E8 ?? ?? ?? ?? 48 8B F8 48 85 C0 74 16");
|
||||
this.RequestCharacterInfo = Marshal.GetDelegateForFunctionPointer<RequestCharInfoDelegate>(rciPtr);
|
||||
if (scanner.ScanTextSafe(Signatures.RequestCharacterInfo, out var rciPtr, "Examine")) {
|
||||
this.RequestCharacterInfo = Marshal.GetDelegateForFunctionPointer<RequestCharInfoDelegate>(rciPtr);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr FollowPtrChain(IntPtr start, IEnumerable<int> offsets) {
|
||||
|
@ -40,6 +45,7 @@ namespace XivCommon.Functions {
|
|||
/// Opens the Examine window for the specified actor.
|
||||
/// </summary>
|
||||
/// <param name="actor">Actor to open window for</param>
|
||||
/// <exception cref="InvalidOperationException">If the signature for this function could not be found</exception>
|
||||
public void OpenExamineWindow(Actor actor) {
|
||||
this.OpenExamineWindow(actor.ActorId);
|
||||
}
|
||||
|
@ -48,7 +54,12 @@ namespace XivCommon.Functions {
|
|||
/// Opens the Examine window for the actor with the specified ID.
|
||||
/// </summary>
|
||||
/// <param name="actorId">Actor ID to open window for</param>
|
||||
/// <exception cref="InvalidOperationException">If the signature for this function could not be found</exception>
|
||||
public void OpenExamineWindow(int actorId) {
|
||||
if (this.RequestCharacterInfo == null) {
|
||||
throw new InvalidOperationException("Could not find signature for Examine function");
|
||||
}
|
||||
|
||||
// NOTES LAST UPDATED: 5.45
|
||||
|
||||
// offsets and stuff come from the beginning of case 0x2c (around line 621 in IDA)
|
||||
|
|
|
@ -12,11 +12,16 @@ namespace XivCommon.Functions {
|
|||
/// A class containing Party Finder functionality
|
||||
/// </summary>
|
||||
public class PartyFinder : IDisposable {
|
||||
private static class Signatures {
|
||||
internal const string RequestListings = "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 0F 10 81 ?? ?? ?? ??";
|
||||
internal const string JoinCrossParty = "E8 ?? ?? ?? ?? 0F B7 47 28";
|
||||
}
|
||||
|
||||
private delegate byte RequestPartyFinderListingsDelegate(IntPtr agent, byte categoryIdx);
|
||||
|
||||
private delegate IntPtr JoinPfDelegate(IntPtr manager, IntPtr a2, int type, IntPtr packetData, uint a5);
|
||||
|
||||
private RequestPartyFinderListingsDelegate RequestPartyFinderListings { get; }
|
||||
private RequestPartyFinderListingsDelegate? RequestPartyFinderListings { get; }
|
||||
private Hook<RequestPartyFinderListingsDelegate>? RequestPfListingsHook { get; }
|
||||
private Hook<JoinPfDelegate>? JoinPfHook { get; }
|
||||
|
||||
|
@ -48,21 +53,22 @@ namespace XivCommon.Functions {
|
|||
this.ListingsEnabled = hooks.HasFlag(Hooks.PartyFinderListings);
|
||||
this.JoinsEnabled = hooks.HasFlag(Hooks.PartyFinderJoins);
|
||||
|
||||
var requestPfPtr = scanner.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 40 0F 10 81 ?? ?? ?? ??");
|
||||
if (scanner.ScanTextSafe(Signatures.RequestListings, out var requestPfPtr, "Party Finder listings")) {
|
||||
this.RequestPartyFinderListings = Marshal.GetDelegateForFunctionPointer<RequestPartyFinderListingsDelegate>(requestPfPtr);
|
||||
|
||||
this.RequestPartyFinderListings = Marshal.GetDelegateForFunctionPointer<RequestPartyFinderListingsDelegate>(requestPfPtr);
|
||||
|
||||
if (this.ListingsEnabled) {
|
||||
this.RequestPfListingsHook = new Hook<RequestPartyFinderListingsDelegate>(requestPfPtr, new RequestPartyFinderListingsDelegate(this.OnRequestPartyFinderListings));
|
||||
this.RequestPfListingsHook.Enable();
|
||||
if (this.ListingsEnabled) {
|
||||
this.RequestPfListingsHook = new Hook<RequestPartyFinderListingsDelegate>(requestPfPtr, new RequestPartyFinderListingsDelegate(this.OnRequestPartyFinderListings));
|
||||
this.RequestPfListingsHook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.JoinsEnabled) {
|
||||
var joinPtr = scanner.ScanText("E8 ?? ?? ?? ?? 0F B7 47 28");
|
||||
this.JoinPfHook = new Hook<JoinPfDelegate>(joinPtr, new JoinPfDelegate(this.JoinPfDetour));
|
||||
this.JoinPfHook.Enable();
|
||||
if (scanner.ScanTextSafe(Signatures.JoinCrossParty, out var joinPtr, "Party Finder joins")) {
|
||||
this.JoinPfHook = new Hook<JoinPfDelegate>(joinPtr, new JoinPfDelegate(this.JoinPfDetour));
|
||||
this.JoinPfHook.Enable();
|
||||
|
||||
this.PartyFinderGui.ReceiveListing += this.ReceiveListing;
|
||||
this.PartyFinderGui.ReceiveListing += this.ReceiveListing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,8 +127,12 @@ namespace XivCommon.Functions {
|
|||
/// This maintains the currently selected category.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">If the <see cref="Hooks.PartyFinderListings"/> hook is not enabled</exception>
|
||||
/// <exception cref="InvalidOperationException">If the <see cref="Hooks.PartyFinderListings"/> hook is not enabled or if the signature for this function could not be found</exception>
|
||||
public void RefreshListings() {
|
||||
if (this.RequestPartyFinderListings == null) {
|
||||
throw new InvalidOperationException("Could not find signature for Party Finder listings");
|
||||
}
|
||||
|
||||
if (!this.ListingsEnabled) {
|
||||
throw new InvalidOperationException("PartyFinder hooks are not enabled");
|
||||
}
|
||||
|
|
|
@ -10,6 +10,11 @@ namespace XivCommon.Functions {
|
|||
/// Class containing Talk events
|
||||
/// </summary>
|
||||
public class Talk : IDisposable {
|
||||
private static class Signatures {
|
||||
internal const string SetAtkValue = "E8 ?? ?? ?? ?? 41 03 ED";
|
||||
internal const string ShowMessageBox = "4C 8B DC 55 57 41 55 49 8D 6B 98";
|
||||
}
|
||||
|
||||
// Updated: 5.5
|
||||
private const int TextOffset = 0;
|
||||
private const int NameOffset = 0x10;
|
||||
|
@ -23,7 +28,7 @@ namespace XivCommon.Functions {
|
|||
|
||||
private delegate IntPtr SetAtkValueStringDelegate(IntPtr atkValue, IntPtr text);
|
||||
|
||||
private SetAtkValueStringDelegate SetAtkValueString { get; }
|
||||
private SetAtkValueStringDelegate SetAtkValueString { get; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The delegate for Talk events.
|
||||
|
@ -43,16 +48,20 @@ namespace XivCommon.Functions {
|
|||
internal Talk(SigScanner scanner, SeStringManager manager, bool hooksEnabled) {
|
||||
this.SeStringManager = manager;
|
||||
|
||||
var setAtkPtr = scanner.ScanText("E8 ?? ?? ?? ?? 41 03 ED");
|
||||
this.SetAtkValueString = Marshal.GetDelegateForFunctionPointer<SetAtkValueStringDelegate>(setAtkPtr);
|
||||
if (scanner.ScanTextSafe(Signatures.SetAtkValue, out var setAtkPtr, "Talk - set atk value")) {
|
||||
this.SetAtkValueString = Marshal.GetDelegateForFunctionPointer<SetAtkValueStringDelegate>(setAtkPtr);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hooksEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var showMessageBoxPtr = scanner.ScanText("4C 8B DC 55 57 41 55 49 8D 6B 98");
|
||||
this.AddonTalkV45Hook = new Hook<AddonTalkV45Delegate>(showMessageBoxPtr, new AddonTalkV45Delegate(this.AddonTalkV45Detour));
|
||||
this.AddonTalkV45Hook.Enable();
|
||||
if (scanner.ScanTextSafe(Signatures.ShowMessageBox, out var showMessageBoxPtr, "Talk")) {
|
||||
this.AddonTalkV45Hook = new Hook<AddonTalkV45Delegate>(showMessageBoxPtr, new AddonTalkV45Delegate(this.AddonTalkV45Detour));
|
||||
this.AddonTalkV45Hook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
30
XivCommon/SigScannerExt.cs
Executable file
30
XivCommon/SigScannerExt.cs
Executable file
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Plugin;
|
||||
|
||||
namespace XivCommon {
|
||||
internal static class SigScannerExt {
|
||||
/// <summary>
|
||||
/// Scan for a signature in memory.
|
||||
/// </summary>
|
||||
/// <param name="scanner">SigScanner to use for scanning</param>
|
||||
/// <param name="sig">signature to search for</param>
|
||||
/// <param name="result">pointer where signature was found or <see cref="IntPtr.Zero"/> if not found</param>
|
||||
/// <param name="name">name of this signature - if specified, a warning will be printed if the signature could not be found</param>
|
||||
/// <returns>true if signature was found</returns>
|
||||
internal static bool ScanTextSafe(this SigScanner scanner, string sig, out IntPtr result, string? name = null) {
|
||||
result = IntPtr.Zero;
|
||||
try {
|
||||
result = scanner.ScanText(sig);
|
||||
return true;
|
||||
} catch (KeyNotFoundException) {
|
||||
if (name != null) {
|
||||
Util.PrintMissingSig(name);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Plugin;
|
||||
|
||||
namespace XivCommon {
|
||||
internal static class Util {
|
||||
public static byte[] Terminate(this byte[] array) {
|
||||
internal static byte[] Terminate(this byte[] array) {
|
||||
var terminated = new byte[array.Length + 1];
|
||||
Array.Copy(array, terminated, array.Length);
|
||||
terminated[terminated.Length - 1] = 0;
|
||||
|
@ -11,7 +12,7 @@ namespace XivCommon {
|
|||
return terminated;
|
||||
}
|
||||
|
||||
public static unsafe byte[] ReadTerminated(IntPtr memory) {
|
||||
internal static unsafe byte[] ReadTerminated(IntPtr memory) {
|
||||
var buf = new List<byte>();
|
||||
|
||||
var ptr = (byte*) memory;
|
||||
|
@ -22,5 +23,9 @@ namespace XivCommon {
|
|||
|
||||
return buf.ToArray();
|
||||
}
|
||||
|
||||
internal static void PrintMissingSig(string name) {
|
||||
PluginLog.LogWarning($"Could not find signature for {name}. This functionality will be disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user