221 lines
7.9 KiB
C#
Executable File
221 lines
7.9 KiB
C#
Executable File
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using Dalamud.Game;
|
|
using Dalamud.Game.ClientState;
|
|
using Dalamud.Game.ClientState.Objects;
|
|
using Dalamud.Game.Gui;
|
|
using Dalamud.Game.Gui.PartyFinder;
|
|
using XivCommon.Functions;
|
|
using XivCommon.Functions.ContextMenu;
|
|
using XivCommon.Functions.FriendList;
|
|
using XivCommon.Functions.NamePlates;
|
|
using XivCommon.Functions.Tooltips;
|
|
|
|
namespace XivCommon {
|
|
/// <summary>
|
|
/// A class containing game functions
|
|
/// </summary>
|
|
public class GameFunctions : IDisposable {
|
|
private static class Signatures {
|
|
internal const string GetAgentByInternalId = "E8 ?? ?? ?? ?? 83 FF 0D";
|
|
internal const string GetAtkStageSingleton = "E8 ?? ?? ?? ?? 41 B8 01 00 00 00 48 8D 15 ?? ?? ?? ?? 48 8B 48 20 E8 ?? ?? ?? ?? 48 8B CF";
|
|
}
|
|
|
|
private delegate IntPtr GetAtkStageSingletonDelegate();
|
|
|
|
private delegate IntPtr GetAgentModuleDelegate(IntPtr basePtr);
|
|
|
|
private delegate IntPtr GetAtkModuleDelegate(IntPtr uiModule);
|
|
|
|
private delegate IntPtr GetAgentByInternalIdDelegate(IntPtr agentModule, uint id);
|
|
|
|
private GameGui GameGui { get; }
|
|
|
|
private GetAgentByInternalIdDelegate? GetAgentByInternalIdInternal { get; }
|
|
|
|
private GetAtkStageSingletonDelegate? GetAtkStageSingletonInternal { get; }
|
|
|
|
internal UiAlloc UiAlloc { get; }
|
|
|
|
/// <summary>
|
|
/// Chat functions
|
|
/// </summary>
|
|
public Chat Chat { get; }
|
|
|
|
/// <summary>
|
|
/// Party Finder functions and events
|
|
/// </summary>
|
|
public PartyFinder PartyFinder { get; }
|
|
|
|
/// <summary>
|
|
/// BattleTalk functions and events
|
|
/// </summary>
|
|
public BattleTalk BattleTalk { get; }
|
|
|
|
/// <summary>
|
|
/// Examine functions
|
|
/// </summary>
|
|
public Examine Examine { get; }
|
|
|
|
/// <summary>
|
|
/// Talk events
|
|
/// </summary>
|
|
public Talk Talk { get; }
|
|
|
|
/// <summary>
|
|
/// Chat bubble functions and events
|
|
/// </summary>
|
|
public ChatBubbles ChatBubbles { get; }
|
|
|
|
/// <summary>
|
|
/// Context menu functions
|
|
/// </summary>
|
|
public ContextMenu ContextMenu { get; }
|
|
|
|
/// <summary>
|
|
/// Tooltip events
|
|
/// </summary>
|
|
public Tooltips Tooltips { get; }
|
|
|
|
/// <summary>
|
|
/// Name plate tools and events
|
|
/// </summary>
|
|
public NamePlates NamePlates { get; }
|
|
|
|
/// <summary>
|
|
/// Duty Finder functions
|
|
/// </summary>
|
|
public DutyFinder DutyFinder { get; }
|
|
|
|
/// <summary>
|
|
/// Friend list functions
|
|
/// </summary>
|
|
public FriendList FriendList { get; }
|
|
|
|
/// <summary>
|
|
/// Journal functions
|
|
/// </summary>
|
|
public Journal Journal { get; }
|
|
|
|
internal GameFunctions(Hooks hooks) {
|
|
this.GameGui = Util.GetService<GameGui>();
|
|
|
|
var clientState = Util.GetService<ClientState>();
|
|
var objectTable = Util.GetService<ObjectTable>();
|
|
var partyFinderGui = Util.GetService<PartyFinderGui>();
|
|
var scanner = Util.GetService<SigScanner>();
|
|
|
|
this.UiAlloc = new UiAlloc(scanner);
|
|
this.Chat = new Chat(this, 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.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);
|
|
|
|
if (scanner.TryScanText(Signatures.GetAgentByInternalId, out var byInternalIdPtr, "GetAgentByInternalId")) {
|
|
this.GetAgentByInternalIdInternal = Marshal.GetDelegateForFunctionPointer<GetAgentByInternalIdDelegate>(byInternalIdPtr);
|
|
}
|
|
|
|
if (scanner.TryScanText(Signatures.GetAtkStageSingleton, out var getSingletonPtr, "GetAtkStageSingleton")) {
|
|
this.GetAtkStageSingletonInternal = Marshal.GetDelegateForFunctionPointer<GetAtkStageSingletonDelegate>(getSingletonPtr);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public void Dispose() {
|
|
this.NamePlates.Dispose();
|
|
this.Tooltips.Dispose();
|
|
this.ContextMenu.Dispose();
|
|
this.ChatBubbles.Dispose();
|
|
this.Talk.Dispose();
|
|
this.BattleTalk.Dispose();
|
|
this.PartyFinder.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the pointer to the UI module
|
|
/// </summary>
|
|
/// <returns>Pointer</returns>
|
|
public IntPtr GetUiModule() {
|
|
return this.GameGui.GetUIModule();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the pointer to the RaptureAtkModule
|
|
/// </summary>
|
|
/// <returns>Pointer</returns>
|
|
public IntPtr GetAtkModule() {
|
|
var uiModule = this.GetUiModule();
|
|
if (uiModule == IntPtr.Zero) {
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
var getAtkModulePtr = FollowPtrChain(uiModule, new[] { 0, 0x38 });
|
|
if (getAtkModulePtr == IntPtr.Zero) {
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
var getAtkModule = Marshal.GetDelegateForFunctionPointer<GetAtkModuleDelegate>(getAtkModulePtr);
|
|
return getAtkModule(uiModule);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the pointer to the agent module
|
|
/// </summary>
|
|
/// <returns>Pointer</returns>
|
|
public IntPtr GetAgentModule() {
|
|
var uiModule = this.GetUiModule();
|
|
var getAgentModulePtr = FollowPtrChain(uiModule, new[] { 0, 0x110 });
|
|
var getAgentModule = Marshal.GetDelegateForFunctionPointer<GetAgentModuleDelegate>(getAgentModulePtr);
|
|
return getAgentModule(uiModule);
|
|
}
|
|
|
|
private static IntPtr FollowPtrChain(IntPtr start, IEnumerable<int> offsets) {
|
|
foreach (var offset in offsets) {
|
|
start = Marshal.ReadIntPtr(start, offset);
|
|
if (start == IntPtr.Zero) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return start;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the pointer to an agent from its internal ID.
|
|
/// </summary>
|
|
/// <param name="id">internal id of agent</param>
|
|
/// <returns>Pointer</returns>
|
|
/// <exception cref="InvalidOperationException">if the signature for the function could not be found</exception>
|
|
public IntPtr GetAgentByInternalId(uint id) {
|
|
if (this.GetAgentByInternalIdInternal == null) {
|
|
throw new InvalidOperationException("Could not find signature for GetAgentByInternalId");
|
|
}
|
|
|
|
var agent = this.GetAgentModule();
|
|
return this.GetAgentByInternalIdInternal(agent, id);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the pointer to the AtkStage singleton
|
|
/// </summary>
|
|
/// <returns>Pointer</returns>
|
|
/// <exception cref="InvalidOperationException">if the signature for the function could not be found</exception>
|
|
public IntPtr GetAtkStageSingleton() {
|
|
if (this.GetAtkStageSingletonInternal == null) {
|
|
throw new InvalidOperationException("Could not find signature for GetAtkStageSingleton");
|
|
}
|
|
|
|
return this.GetAtkStageSingletonInternal();
|
|
}
|
|
}
|
|
}
|