Skip to content

Instantly share code, notes, and snippets.

@CamxxCore
Last active July 1, 2023 18:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CamxxCore/d874e2facf85a0f911ba847f939abc9e to your computer and use it in GitHub Desktop.
Save CamxxCore/d874e2facf85a0f911ba847f939abc9e to your computer and use it in GitHub Desktop.
Memory class the retrieve the name of a currently playing animation
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