Last active
July 1, 2023 18:00
-
-
Save CamxxCore/d874e2facf85a0f911ba847f939abc9e to your computer and use it in GitHub Desktop.
Memory class the retrieve the name of a currently playing animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
namespace Memory | |
{ | |
public static class MemoryAccess | |
{ | |
private delegate int GetAnimDictIndex(ref int index, int dictionaryHash); | |
private delegate IntPtr GetAnimClipForDictionaryIndex(int index, int clipHash); | |
private delegate IntPtr CTaskTree__GetTaskInstance(IntPtr taskTree, int taskId); | |
private static readonly GetAnimDictIndex _getAnimDictIndex; | |
private static readonly GetAnimClipForDictionaryIndex _getAnimClipForDictionary; | |
private static readonly CTaskTree__GetTaskInstance _getTaskInstance; | |
private static readonly int _pedIntelligenceOffset; | |
static MemoryAccess() | |
{ | |
var pattern = new Pattern("\x83\xCB\x02\x44\x38\xA7\x00\x00\x00\x00", "xxxxxx????"); | |
var address = pattern.Get(-15); | |
address = address + Marshal.ReadInt32(address) + 4; | |
_getAnimClipForDictionary = | |
Marshal.GetDelegateForFunctionPointer<GetAnimClipForDictionaryIndex>(address); | |
address = pattern.Get(-33); | |
address = address + Marshal.ReadInt32(address) + 4; | |
_getAnimDictIndex = | |
Marshal.GetDelegateForFunctionPointer<GetAnimDictIndex>(address); | |
pattern = new Pattern("\x4C\x8B\xF0\x48\x85\xC0\x74\x7E", "xxxxxxxx"); | |
address = pattern.Get(-4); | |
address = address + Marshal.ReadInt32(address) + 4; | |
_getTaskInstance = Marshal.GetDelegateForFunctionPointer<CTaskTree__GetTaskInstance>(address); | |
address = pattern.Get(-21); | |
_pedIntelligenceOffset = Marshal.ReadInt32(address); | |
} | |
public static IntPtr GetPedTaskTree(IntPtr ped, int taskTreeIndex) | |
{ | |
var pedIntelligence = Marshal.ReadIntPtr(ped + _pedIntelligenceOffset); | |
return pedIntelligence == IntPtr.Zero ? | |
IntPtr.Zero : Marshal.ReadIntPtr(pedIntelligence + 0x360 + taskTreeIndex * 8); | |
} | |
public static IntPtr GetPedTask(IntPtr ped, int taskId) | |
{ | |
var taskTree = GetPedTaskTree(ped, 0); //CTaskTreePed | |
return taskTree != IntPtr.Zero ? | |
_getTaskInstance(taskTree, taskId) : IntPtr.Zero; | |
} | |
public static int GetScriptedAnimationDictionary(IntPtr ped) | |
{ | |
var task = GetPedTask(ped, 134); //CTaskScriptedAnimation | |
if (task != IntPtr.Zero) | |
{ | |
return Marshal.ReadInt32(task + 244); | |
} | |
return -1; | |
} | |
public static string GetScriptedAnimationName(IntPtr ped) | |
{ | |
var task = GetPedTask(ped, 134); //CTaskScriptedAnimation | |
if (task == IntPtr.Zero) return "notask"; | |
int index = -1; | |
var dictionaryIndex = _getAnimDictIndex(ref index, Marshal.ReadInt32(task + 244)); | |
if (dictionaryIndex != -1) | |
{ | |
var animClip = _getAnimClipForDictionary(index, Marshal.ReadInt32(task + 248)); | |
if (animClip != IntPtr.Zero) | |
{ | |
string result = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(animClip + 0x18)); | |
int idx = result.IndexOf('/') + 1; | |
return result.Substring(idx, result.IndexOf(".clip", StringComparison.Ordinal) - idx); | |
} | |
} | |
return "none"; | |
} | |
} | |
public sealed class Pattern | |
{ | |
private readonly string bytes, mask; | |
private readonly IntPtr result; | |
public Pattern(string bytes, string mask, string moduleName = null) | |
{ | |
this.bytes = bytes; | |
this.mask = mask; | |
this.result = FindPattern(moduleName); | |
} | |
private unsafe IntPtr FindPattern(string moduleName) | |
{ | |
Win32Native.MODULEINFO module; | |
Win32Native.GetModuleInformation( | |
Win32Native.GetCurrentProcess(), | |
Win32Native.GetModuleHandle(moduleName), | |
out module, | |
sizeof(Win32Native.MODULEINFO)); | |
var address = module.lpBaseOfDll.ToInt64(); | |
var end = address + module.SizeOfImage; | |
for (; address < end; address++) | |
{ | |
if (bCompare((byte*)(address), bytes.ToCharArray(), mask.ToCharArray())) | |
{ | |
return new IntPtr(address); | |
} | |
} | |
return IntPtr.Zero; | |
} | |
public IntPtr Get(int offset = 0) | |
{ | |
return result + offset; | |
} | |
private static unsafe bool bCompare(byte* pData, char[] bMask, char[] szMask) | |
{ | |
return !bMask.Where((t, i) => szMask[i] == 'x' && pData[i] != t).Any(); | |
} | |
} | |
public static class Win32Native | |
{ | |
[DllImport("kernel32.dll")] | |
public static extern IntPtr GetCurrentProcess(); | |
[DllImport("kernel32.dll", CharSet = CharSet.Auto)] | |
public static extern IntPtr GetModuleHandle(string lpModuleName); | |
[DllImport("psapi.dll", SetLastError = true)] | |
public static extern bool GetModuleInformation(IntPtr hProcess, IntPtr hModule, out MODULEINFO lpmodinfo, int cb); | |
[StructLayout(LayoutKind.Sequential)] | |
public struct MODULEINFO | |
{ | |
public IntPtr lpBaseOfDll; | |
public uint SizeOfImage; | |
public IntPtr EntryPoint; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment