feat: add aers menu thingy

This commit is contained in:
goat 2021-04-26 20:39:09 +02:00
parent b29f837947
commit e930c98769
No known key found for this signature in database
GPG key ID: F18F057873895461
2 changed files with 180 additions and 1 deletions

View file

@ -6,6 +6,7 @@ using System.Threading;
using Dalamud.Configuration;
using Dalamud.Data;
using Dalamud.Game;
using Dalamud.Game.Addon;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.ClientState;
using Dalamud.Game.Command;
@ -164,6 +165,11 @@ namespace Dalamud
/// </summary>
internal NetworkHandlers NetworkHandlers { get; private set; }
/// <summary>
/// Gets subsystem responsible for adding the Dalamud menu items to the game's system menu.
/// </summary>
internal DalamudSystemMenu SystemMenu { get; private set; }
#endregion
/// <summary>
@ -198,7 +204,7 @@ namespace Dalamud
this.AntiDebug = new AntiDebug(this.SigScanner);
#if DEBUG
AntiDebug.Enable();
this.AntiDebug.Enable();
#endif
Log.Information("[START] AntiDebug OK!");
@ -315,6 +321,9 @@ namespace Dalamud
Log.Information("[START] DUI OK!");
this.SystemMenu = new DalamudSystemMenu(this);
this.SystemMenu.Enable();
this.IsReady = true;
Troubleshooting.LogTroubleshooting(this, isInterfaceLoaded);
@ -404,6 +413,8 @@ namespace Dalamud
this.AntiDebug?.Dispose();
this.SystemMenu?.Dispose();
Log.Debug("Dalamud::Dispose() OK!");
}
catch (Exception ex)

View file

@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Dalamud.Hooking;
using FFXIVClientStructs.FFXIV.Component.GUI;
using ValueType = FFXIVClientStructs.FFXIV.Component.GUI.ValueType;
namespace Dalamud.Game.Addon
{
internal unsafe class DalamudSystemMenu
{
private readonly Dalamud dalamud;
private delegate void AgentHudOpenSystemMenuProtoype(void* thisPtr, AtkValue* atkValueArgs, uint menuSize);
private Hook<AgentHudOpenSystemMenuProtoype> hookAgentHudOpenSystemMenu;
private delegate void AtkValueChangeType(AtkValue* thisPtr, ValueType type);
private AtkValueChangeType atkValueChangeType;
private delegate void AtkValueSetString(AtkValue* thisPtr, byte* bytes);
private AtkValueSetString atkValueSetString;
private delegate void UiModuleRequestMainCommand(void* thisPtr, int commandId);
// TODO: Make this into events in Framework.Gui
private Hook<UiModuleRequestMainCommand> hookUiModuleRequestMainCommand;
/// <summary>
/// Initializes a new instance of the <see cref="DalamudSystemMenu"/> class.
/// </summary>
/// <param name="dalamud">The dalamud instance to act on.</param>
public DalamudSystemMenu(Dalamud dalamud)
{
this.dalamud = dalamud;
var openSystemMenuAddress = this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 32 C0 4C 8B AC 24 ?? ?? ?? ?? 48 8B 8D ?? ?? ?? ??");
this.hookAgentHudOpenSystemMenu = new Hook<AgentHudOpenSystemMenuProtoype>(
openSystemMenuAddress,
new AgentHudOpenSystemMenuProtoype(this.AgentHudOpenSystemMenuDetour),
this);
var atkValueChangeTypeAddress =
this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 45 84 F6 48 8D 4C 24 ??");
this.atkValueChangeType =
Marshal.GetDelegateForFunctionPointer<AtkValueChangeType>(atkValueChangeTypeAddress);
var atkValueSetStringAddress =
this.dalamud.SigScanner.ScanText("E8 ?? ?? ?? ?? 41 03 ED");
this.atkValueSetString = Marshal.GetDelegateForFunctionPointer<AtkValueSetString>(atkValueSetStringAddress);
var uiModuleRequestMainCommmandAddress = this.dalamud.SigScanner.ScanText(
"40 53 56 48 81 EC ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? ?? ?? 48 8B 01 8B DA 48 8B F1 FF 90 ?? ?? ?? ??");
this.hookUiModuleRequestMainCommand = new Hook<UiModuleRequestMainCommand>(
uiModuleRequestMainCommmandAddress,
new UiModuleRequestMainCommand(this.UiModuleRequestMainCommandDetour),
this);
}
public void Enable()
{
this.hookAgentHudOpenSystemMenu.Enable();
this.hookUiModuleRequestMainCommand.Enable();
}
private void AgentHudOpenSystemMenuDetour(void* thisPtr, AtkValue* atkValueArgs, uint menuSize)
{
// the max size (hardcoded) is 0xE/15, but the system menu currently uses 0xC/12
// this is a just in case that doesnt really matter
// see if we can add 2 entries
if (menuSize >= 0xD)
{
hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize);
return;
}
// atkValueArgs is actually an array of AtkValues used as args. all their UI code works like this.
// in this case, menu size is stored in atkValueArgs[4], and the next 15 slots are the MainCommand
// the 15 slots after that, if they exist, are the entry names, but they are otherwise pulled from MainCommand EXD
// reference the original function for more details :)
// step 1) move all the current menu items down so we can put Dalamud at the top like it deserves
atkValueChangeType(&atkValueArgs[menuSize + 5], ValueType.Int); // currently this value has no type, set it to int
atkValueChangeType(&atkValueArgs[menuSize + 5 + 1], ValueType.Int);
for (uint i = menuSize+2; i > 1; i--)
{
var curEntry = &atkValueArgs[i + 5 - 2];
var nextEntry = &atkValueArgs[i + 5];
nextEntry->Int = curEntry->Int;
}
// step 2) set our new entries to dummy commands
var firstEntry = &atkValueArgs[5];
firstEntry->Int = 69420;
var secondEntry = &atkValueArgs[6];
secondEntry->Int = 69421;
// step 3) create strings for them
// since the game first checks for strings in the AtkValue argument before pulling them from the exd, if we create strings we dont have to worry
// about hooking the exd reader, thank god
var firstStringEntry = &atkValueArgs[5 + 15];
atkValueChangeType(firstStringEntry, ValueType.String);
var secondStringEntry = &atkValueArgs[6 + 15];
atkValueChangeType(secondStringEntry, ValueType.String);
// do this the most terrible way possible since im lazy
var bytes = stackalloc byte[17];
Marshal.Copy(System.Text.Encoding.ASCII.GetBytes("Dalamud Settings"), 0, new IntPtr(bytes), 16);
bytes[16] = 0x0;
atkValueSetString(firstStringEntry, bytes); // this allocs the string properly using the game's allocators and copies it, so we dont have to worry about memory fuckups
var bytes2 = stackalloc byte[16];
Marshal.Copy(System.Text.Encoding.ASCII.GetBytes("Dalamud Plugins"), 0, new IntPtr(bytes2), 15);
bytes2[15] = 0x0;
atkValueSetString(secondStringEntry, bytes2);
// open menu with new size
var sizeEntry = &atkValueArgs[4];
sizeEntry->UInt = menuSize + 2;
this.hookAgentHudOpenSystemMenu.Original(thisPtr, atkValueArgs, menuSize + 2);
}
private void UiModuleRequestMainCommandDetour(void* thisPtr, int commandId)
{
if (commandId == 69420)
{
this.dalamud.DalamudUi.OpenSettings();
}
else if (commandId == 69421)
{
this.dalamud.DalamudUi.OpenPluginInstaller();
}
else
{
this.hookUiModuleRequestMainCommand.Original(thisPtr, commandId);
}
}
#region IDisposable Support
protected virtual void Dispose(bool disposing)
{
if (!disposing) return;
this.hookAgentHudOpenSystemMenu.Dispose();
this.hookUiModuleRequestMainCommand.Dispose();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}