diff --git a/XivCommon/Functions/Chat.cs b/XivCommon/Functions/Chat.cs index 03392a5..07be90c 100755 --- a/XivCommon/Functions/Chat.cs +++ b/XivCommon/Functions/Chat.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Text; using Dalamud.Game; +using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework; namespace XivCommon.Functions { /// @@ -13,31 +14,35 @@ namespace XivCommon.Functions { 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; } - internal Chat(GameFunctions functions, SigScanner scanner) { - this.Functions = functions; - + internal Chat(SigScanner scanner) { if (scanner.TryScanText(Signatures.SendChat, out var processChatBoxPtr, "chat sending")) { this.ProcessChatBox = Marshal.GetDelegateForFunctionPointer(processChatBoxPtr); } } /// + /// /// Send a given message to the chat box. This can send chat to the server. + /// + /// + /// This method is unsafe. This method does no checking on your input and + /// may send content to the server that the normal client could not. You must + /// verify what you're sending and handle content and length to properly use + /// this. + /// /// /// Message to send /// If the signature for this function could not be found - public unsafe void SendMessage(string message) { + public unsafe void SendMessageUnsafe(byte[] message) { if (this.ProcessChatBox == null) { throw new InvalidOperationException("Could not find signature for chat sending"); } - var uiModule = (IntPtr) this.Functions.GetFramework()->GetUiModule(); + var uiModule = (IntPtr) Framework.Instance()->GetUiModule(); using var payload = new ChatPayload(message); var mem1 = Marshal.AllocHGlobal(400); @@ -48,6 +53,32 @@ namespace XivCommon.Functions { Marshal.FreeHGlobal(mem1); } + /// + /// + /// Send a given message to the chat box. This can send chat to the server. + /// + /// + /// This method is slightly less unsafe than . It + /// will throw exceptions for certain inputs that the client can't normally send, + /// but it is still possible to make mistakes. Use with caution. + /// + /// + /// + /// If is empty or longer than 500 bytes in UTF-8. + /// If the signature for this function could not be found + public void SendMessage(string message) { + var bytes = Encoding.UTF8.GetBytes(message); + if (bytes.Length == 0) { + throw new ArgumentException("message is empty", nameof(message)); + } + + if (bytes.Length > 500) { + throw new ArgumentException("message is longer than 500 bytes", nameof(message)); + } + + this.SendMessageUnsafe(bytes); + } + [StructLayout(LayoutKind.Explicit)] [SuppressMessage("ReSharper", "PrivateFieldCanBeConvertedToLocalVariable")] private readonly struct ChatPayload : IDisposable { @@ -63,8 +94,7 @@ namespace XivCommon.Functions { [FieldOffset(24)] private readonly ulong unk2; - internal ChatPayload(string text) { - var stringBytes = Encoding.UTF8.GetBytes(text); + internal ChatPayload(byte[] stringBytes) { this.textPtr = Marshal.AllocHGlobal(stringBytes.Length + 30); Marshal.Copy(stringBytes, 0, this.textPtr, stringBytes.Length); Marshal.WriteByte(this.textPtr + stringBytes.Length, 0); diff --git a/XivCommon/Functions/ContextMenu/ContextMenu.cs b/XivCommon/Functions/ContextMenu/ContextMenu.cs index bfd029a..f5ea986 100755 --- a/XivCommon/Functions/ContextMenu/ContextMenu.cs +++ b/XivCommon/Functions/ContextMenu/ContextMenu.cs @@ -11,6 +11,7 @@ using Dalamud.Hooking; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Component.GUI; using XivCommon.Functions.ContextMenu.Inventory; +using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework; using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType; namespace XivCommon.Functions.ContextMenu { @@ -286,7 +287,7 @@ namespace XivCommon.Functions.ContextMenu { agent ??= this.Agent; IntPtr GetAgent(AgentId id) { - return (IntPtr) this.Functions.GetFramework()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(id); + return (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(id); } var agentType = AgentType.Unknown; diff --git a/XivCommon/Functions/DutyFinder.cs b/XivCommon/Functions/DutyFinder.cs index 23ba4ef..cbf930b 100755 --- a/XivCommon/Functions/DutyFinder.cs +++ b/XivCommon/Functions/DutyFinder.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using Dalamud.Game; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using Lumina.Excel.GeneratedSheets; +using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework; namespace XivCommon.Functions { /// @@ -18,13 +19,10 @@ namespace XivCommon.Functions { private delegate IntPtr OpenRouletteDelegate(IntPtr agent, byte roulette, byte a3); - private GameFunctions Functions { get; } private readonly OpenDutyDelegate? _openDuty; private readonly OpenRouletteDelegate? _openRoulette; - internal DutyFinder(GameFunctions functions, SigScanner scanner) { - this.Functions = functions; - + internal DutyFinder(SigScanner scanner) { if (scanner.TryScanText(Signatures.OpenRegularDuty, out var openDutyPtr, "Duty Finder (open duty)")) { this._openDuty = Marshal.GetDelegateForFunctionPointer(openDutyPtr); } @@ -53,7 +51,7 @@ namespace XivCommon.Functions { throw new InvalidOperationException("Could not find signature for open duty function"); } - var agent = (IntPtr) this.Functions.GetFramework()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ContentsFinder); + var agent = (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ContentsFinder); this._openDuty(agent, contentFinderCondition, 0); } @@ -75,7 +73,7 @@ namespace XivCommon.Functions { throw new InvalidOperationException("Could not find signature for open roulette function"); } - var agent = (IntPtr) this.Functions.GetFramework()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ContentsFinder); + var agent = (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.ContentsFinder); this._openRoulette(agent, roulette, 0); } diff --git a/XivCommon/Functions/Examine.cs b/XivCommon/Functions/Examine.cs index 309d12d..f25557b 100755 --- a/XivCommon/Functions/Examine.cs +++ b/XivCommon/Functions/Examine.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using Dalamud.Game; using Dalamud.Game.ClientState.Objects.Types; +using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework; namespace XivCommon.Functions { /// @@ -12,15 +13,11 @@ namespace XivCommon.Functions { 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 long RequestCharInfoDelegate(IntPtr ptr); private RequestCharInfoDelegate? RequestCharacterInfo { get; } - internal Examine(GameFunctions functions, SigScanner scanner) { - this.Functions = functions; - + internal Examine(SigScanner scanner) { // got this by checking what accesses rciData below if (scanner.TryScanText(Signatures.RequestCharacterInfo, out var rciPtr, "Examine")) { this.RequestCharacterInfo = Marshal.GetDelegateForFunctionPointer(rciPtr); @@ -51,7 +48,7 @@ namespace XivCommon.Functions { // offsets and stuff come from the beginning of case 0x2c (around line 621 in IDA) // if 29f8 ever changes, I'd just scan for it in old binary and find what it is in the new binary at the same spot // 40 55 53 57 41 54 41 55 41 56 48 8D 6C 24 ?? - var agentModule = (IntPtr) this.Functions.GetFramework()->GetUiModule()->GetAgentModule(); + var agentModule = (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule(); var rciData = Marshal.ReadIntPtr(agentModule + 0x1A0); // offsets at sig E8 ?? ?? ?? ?? 33 C0 EB 4C diff --git a/XivCommon/Functions/FriendList/FriendList.cs b/XivCommon/Functions/FriendList/FriendList.cs index 2e926d4..7134971 100755 --- a/XivCommon/Functions/FriendList/FriendList.cs +++ b/XivCommon/Functions/FriendList/FriendList.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI.Agent; namespace XivCommon.Functions.FriendList { @@ -12,8 +13,6 @@ namespace XivCommon.Functions.FriendList { private const int LengthOffset = 0x10; private const int ListOffset = 0x98; - private GameFunctions Functions { get; } - /// /// /// A live list of the currently-logged-in player's friends. @@ -24,8 +23,7 @@ namespace XivCommon.Functions.FriendList { /// public unsafe IList List { get { - var friendListAgent = (IntPtr) this.Functions - .GetFramework() + var friendListAgent = (IntPtr) Framework.Instance() ->GetUiModule() ->GetAgentModule() ->GetAgentByInternalId(AgentId.FriendList); @@ -58,8 +56,7 @@ namespace XivCommon.Functions.FriendList { } } - internal FriendList(GameFunctions functions) { - this.Functions = functions; + internal FriendList() { } } } diff --git a/XivCommon/Functions/Journal.cs b/XivCommon/Functions/Journal.cs index 5b022fc..f24fcec 100755 --- a/XivCommon/Functions/Journal.cs +++ b/XivCommon/Functions/Journal.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices; using Dalamud.Game; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using Lumina.Excel.GeneratedSheets; +using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework; namespace XivCommon.Functions { /// @@ -14,20 +15,14 @@ namespace XivCommon.Functions { internal const string IsQuestCompleted = "E8 ?? ?? ?? ?? 41 88 84 2C ?? ?? ?? ??"; } - private const int JournalAgentId = 31; - private delegate IntPtr OpenQuestDelegate(IntPtr agent, int questId, int a3, ushort a4, byte a5); private delegate byte IsQuestCompletedDelegate(ushort questId); - private GameFunctions Functions { get; } - private readonly OpenQuestDelegate? _openQuest; private readonly IsQuestCompletedDelegate? _isQuestCompleted; - internal Journal(GameFunctions functions, SigScanner scanner) { - this.Functions = functions; - + internal Journal(SigScanner scanner) { if (scanner.TryScanText(Signatures.OpenQuest, out var openQuestPtr, "Journal (open quest)")) { this._openQuest = Marshal.GetDelegateForFunctionPointer(openQuestPtr); } @@ -56,7 +51,7 @@ namespace XivCommon.Functions { throw new InvalidOperationException("Could not find signature for open quest function"); } - var agent = (IntPtr) this.Functions.GetFramework()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.Journal); + var agent = (IntPtr) Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.Journal); this._openQuest(agent, (int) (questId & 0xFFFF), 1, 0, 1); } diff --git a/XivCommon/Functions/NamePlates/NamePlates.cs b/XivCommon/Functions/NamePlates/NamePlates.cs index a54d273..4fda3c7 100755 --- a/XivCommon/Functions/NamePlates/NamePlates.cs +++ b/XivCommon/Functions/NamePlates/NamePlates.cs @@ -5,6 +5,7 @@ using Dalamud.Game.Text.SeStringHandling; using Dalamud.Hooking; using FFXIVClientStructs.FFXIV.Client.Graphics; using FFXIVClientStructs.FFXIV.Client.UI; +using Framework = FFXIVClientStructs.FFXIV.Client.System.Framework.Framework; namespace XivCommon.Functions.NamePlates { /// @@ -97,7 +98,7 @@ namespace XivCommon.Functions.NamePlates { return; } - var atkModule = this.Functions.GetFramework()->GetUiModule()->GetRaptureAtkModule(); + var atkModule = Framework.Instance()->GetUiModule()->GetRaptureAtkModule(); var active = numbers->IntArray[0]; diff --git a/XivCommon/GameFunctions.cs b/XivCommon/GameFunctions.cs index 81966e5..8ceecac 100755 --- a/XivCommon/GameFunctions.cs +++ b/XivCommon/GameFunctions.cs @@ -100,18 +100,18 @@ namespace XivCommon { var scanner = Util.GetService(); this.UiAlloc = new UiAlloc(scanner); - this.Chat = new Chat(this, scanner); + this.Chat = new Chat(scanner); this.PartyFinder = new PartyFinder(scanner, partyFinderGui, hooks); - this.BattleTalk = new BattleTalk(this, scanner, hooks.HasFlag(Hooks.BattleTalk)); - this.Examine = new Examine(this, scanner); + this.BattleTalk = new BattleTalk(scanner, hooks.HasFlag(Hooks.BattleTalk)); + this.Examine = new Examine(scanner); this.Talk = new Talk(scanner, hooks.HasFlag(Hooks.Talk)); this.ChatBubbles = new ChatBubbles(objectTable, scanner, hooks.HasFlag(Hooks.ChatBubbles)); this.ContextMenu = new ContextMenu(this, scanner, clientState.ClientLanguage, hooks); this.Tooltips = new Tooltips(scanner, this.GameGui, hooks.HasFlag(Hooks.Tooltips)); this.NamePlates = new NamePlates(this, scanner, hooks.HasFlag(Hooks.NamePlates)); - this.DutyFinder = new DutyFinder(this, scanner); - this.Journal = new Journal(this, scanner); - this.FriendList = new FriendList(this); + this.DutyFinder = new DutyFinder(scanner); + this.Journal = new Journal(scanner); + this.FriendList = new FriendList(); this.Housing = new Housing(scanner); } @@ -130,6 +130,7 @@ namespace XivCommon { /// Convenience method to get a pointer to . /// /// pointer to struct + [Obsolete("Use Framework.Instance()")] public unsafe Framework* GetFramework() { return (Framework*) this.Framework.Address.BaseAddress; } @@ -138,7 +139,7 @@ namespace XivCommon { /// Gets the pointer to the UI module /// /// Pointer - [Obsolete("Use GetFramework()->GetUiModule()")] + [Obsolete("Use Framework.Instance()->GetUiModule()")] public unsafe IntPtr GetUiModule() { return (IntPtr) this.GetFramework()->GetUiModule(); } @@ -147,7 +148,7 @@ namespace XivCommon { /// Gets the pointer to the RaptureAtkModule /// /// Pointer - [Obsolete("Use GetFramework()->GetUiModule()->GetRaptureAtkModule()")] + [Obsolete("Use Framework.Instance()->GetUiModule()->GetRaptureAtkModule()")] public unsafe IntPtr GetAtkModule() { return (IntPtr) this.GetFramework()->GetUiModule()->GetRaptureAtkModule(); } @@ -156,7 +157,7 @@ namespace XivCommon { /// Gets the pointer to the agent module /// /// Pointer - [Obsolete("Use GetFramework()->GetUiModule()->GetAgentModule()")] + [Obsolete("Use Framework.Instance()->GetUiModule()->GetAgentModule()")] public unsafe IntPtr GetAgentModule() { return (IntPtr) this.GetFramework()->GetUiModule()->GetAgentModule(); } @@ -167,7 +168,7 @@ namespace XivCommon { /// internal id of agent /// Pointer /// if the signature for the function could not be found - [Obsolete("Use GetFramework()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId)")] + [Obsolete("Use Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId)")] public unsafe IntPtr GetAgentByInternalId(uint id) { return (IntPtr) this.GetFramework()->GetUiModule()->GetAgentModule()->GetAgentByInternalId((AgentId) id); }