Permalink
Cannot retrieve contributors at this time
309 lines (210 sloc)
9.6 KB
| using System; | |
| using System.Collections.Generic; | |
| using System.Runtime.InteropServices; | |
| using System.Runtime.CompilerServices; | |
| using GTA.Math; | |
| namespace MapInfoTool.Memory | |
| { | |
| public class CBuildingWrapped | |
| { | |
| public IntPtr Address { get; set; } | |
| public int ModelHash { get; set; } | |
| public string ModelName { get; set; } | |
| public Vector3 Position { get; set; } | |
| public CMatrix Matrix { get; set; } | |
| } | |
| public class MemoryAccess | |
| { | |
| private static IntPtr _cBuildingPoolPtr, _mapDataStorePtr, _getConstStringForHashPtr; | |
| private static GetConstStringForHashFunc _getStringForHash; | |
| [UnmanagedFunctionPointer(CallingConvention.ThisCall)] | |
| private delegate IntPtr GetEntityObbFunc(IntPtr entity, ref CEntityBounds bounds); | |
| // domain is one of the following | |
| // 1 - Assets (filenames) | |
| // 2 - Code/ dev strings | |
| // 3 - N/A | |
| // 4 - Stat strings | |
| [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | |
| private delegate IntPtr GetConstStringForHashFunc(int domain, uint hashKey); | |
| private const int CBuildingClassSize = 0xD0; | |
| public static void MainInit() | |
| { | |
| #region SetupCBuildingPool | |
| var pattern = new Pattern("\x48\x8B\x05\x00\x00\x00\x00\x8B\x70\x10", "xxx????xxx"); | |
| var result = pattern.Get(); | |
| if (result != IntPtr.Zero) | |
| { | |
| var rip = result.ToInt64() + 7; | |
| var value = Marshal.ReadInt32(IntPtr.Add(result, 3)); | |
| _cBuildingPoolPtr = new IntPtr(rip + value); | |
| } | |
| #endregion | |
| #region SetupMapDataStore | |
| pattern = new Pattern("\x0F\xB7\x04\x79\x66\x83\xE0\x3F", "xxxxxxxx"); | |
| result = pattern.Get(0x13); | |
| if (result != IntPtr.Zero) | |
| { | |
| var rip = result.ToInt64() + 7; | |
| var value = Marshal.ReadInt32(IntPtr.Add(result, 3)); | |
| _mapDataStorePtr = new IntPtr(rip + value); | |
| } | |
| #endregion | |
| #region SetupGetConstString | |
| pattern = new Pattern("\x33\xD2\x41\x0F\x28\xC2", "xxxxxx"); | |
| result = pattern.Get(0x35); | |
| if (result != IntPtr.Zero) | |
| { | |
| var rip = result.ToInt64() + 5; | |
| var value = Marshal.ReadInt32(IntPtr.Add(result, 1)); | |
| _getConstStringForHashPtr = new IntPtr(rip + value); | |
| } | |
| #endregion | |
| _getStringForHash = Marshal.GetDelegateForFunctionPointer<GetConstStringForHashFunc>(_getConstStringForHashPtr); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static Vector3 GetEntityPosition(IntPtr entity) | |
| { | |
| return (Vector3)Marshal.PtrToStructure(entity + 0x90, typeof(Vector3)); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static CMatrix GetEntityMatrix(IntPtr entity) | |
| { | |
| return (CMatrix)Marshal.PtrToStructure(entity + 0x60, typeof(CMatrix)); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static void SetEntityPosition(IntPtr entity, Vector3 position) | |
| { | |
| Marshal.StructureToPtr(position, entity + 0x90, false); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static void SetEntityMatrix(IntPtr entity, CMatrix matrix) | |
| { | |
| Marshal.StructureToPtr(matrix, entity + 0x60, false); | |
| } | |
| [MethodImpl(MethodImplOptions.AggressiveInlining)] | |
| public static void SetEntityEulerRotation(IntPtr entity, Quaternion rotation) | |
| { | |
| var origMatrix = GetEntityMatrix(entity); | |
| var matrix = Matrix.RotationQuaternion(rotation); | |
| matrix.M41 = origMatrix.M41; | |
| matrix.M42 = origMatrix.M42; | |
| matrix.M43 = origMatrix.M43; | |
| SetEntityMatrix(entity, matrix); | |
| } | |
| public static void GetEntityObb(IntPtr entity, out Vector3 min, out Vector3 max) | |
| { | |
| var vfTable = Marshal.ReadIntPtr(entity); | |
| var fnAddress = Marshal.ReadIntPtr(vfTable + 0x1B8); | |
| var fn = Marshal.GetDelegateForFunctionPointer<GetEntityObbFunc>(fnAddress); | |
| var bounds = new CEntityBounds(); | |
| fn(entity, ref bounds); | |
| min = bounds.Min; | |
| max = bounds.Max; | |
| } | |
| public static string GetEntityMapDataName(IntPtr entity) | |
| { | |
| var psoFileIndex = Marshal.ReadInt32(entity + 0xC8) >> 8 & 0xFFFF; | |
| var itemSize = Marshal.ReadInt32(_mapDataStorePtr + 0x4C); | |
| var assetItemPtr = Marshal.ReadIntPtr(_mapDataStorePtr + 0x38) + psoFileIndex * itemSize; | |
| var fileHash = (uint)Marshal.ReadInt32(assetItemPtr + 0xC); | |
| var result = _getStringForHash(1, fileHash); | |
| return Marshal.PtrToStringAnsi(result); | |
| } | |
| public static IEnumerable<string> GetEntityTextureNames(IntPtr entity) | |
| { | |
| var ptr = Marshal.ReadIntPtr(entity + 0x48); //drawHandler | |
| if (ptr == IntPtr.Zero) yield break; | |
| ptr = Marshal.ReadIntPtr(ptr + 0x8); //drawable instance | |
| if (ptr == IntPtr.Zero) yield break; | |
| ptr = Marshal.ReadIntPtr(ptr + 0x10); //shader group | |
| ptr = Marshal.ReadIntPtr(ptr + 0x8); //texture dictionary | |
| var itemStart = Marshal.ReadIntPtr(ptr + 0x30); //items | |
| int numItems = Marshal.ReadInt16(ptr + 0x38); | |
| for (int i = 0; i < numItems; i++) | |
| { | |
| ptr = Marshal.ReadIntPtr(itemStart + i * 8); | |
| yield return Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(ptr + 0x28)); | |
| } | |
| } | |
| public static string GetEntityName(IntPtr address) | |
| { | |
| // probably a better way to get this... | |
| if ((Marshal.ReadByte(address + 0xC0) & 0x40) != 0) | |
| { | |
| var fragInst = Marshal.ReadIntPtr(address + 0x30); | |
| if (fragInst != IntPtr.Zero) | |
| { | |
| var fragType = Marshal.ReadIntPtr(fragInst + 0x78); | |
| if (fragType != IntPtr.Zero) | |
| { | |
| var str = Marshal.ReadIntPtr(fragType + 0x58); | |
| if (str != IntPtr.Zero) | |
| { | |
| var result = Marshal.PtrToStringAnsi(str); | |
| return result?.Substring(result.IndexOf('/') + 1) ?? ""; | |
| } | |
| } | |
| } | |
| } | |
| var drawHandler = Marshal.ReadIntPtr(address + 0x48); | |
| if (drawHandler == IntPtr.Zero) return null; | |
| { | |
| var gtaDrawable = Marshal.ReadIntPtr(drawHandler + 0x8); | |
| if (gtaDrawable == IntPtr.Zero) return null; | |
| var result = Marshal.PtrToStringAnsi(Marshal.ReadIntPtr(gtaDrawable + 0xA8)); | |
| if (result != null) | |
| return result.Substring(0, result.Length - 4); | |
| } | |
| return null; | |
| } | |
| public static IEnumerable<CBuildingWrapped> GetCBuildings() | |
| { | |
| return GetCBuildings(false); | |
| } | |
| public static IEnumerable<CBuildingWrapped> GetCBuildings(Vector3 center, float range) | |
| { | |
| return GetCBuildings(center, range, false); | |
| } | |
| public static IEnumerable<CBuildingWrapped> GetCBuildings(bool getNonDrawables) | |
| { | |
| var baseAddr = Marshal.ReadIntPtr(_cBuildingPoolPtr); | |
| var itemStart = Marshal.ReadIntPtr(baseAddr); | |
| var count = Marshal.ReadInt32(baseAddr + 0x10); | |
| for (int i = 0; i < count; i++) | |
| { | |
| var currentAddr = itemStart + i * CBuildingClassSize; | |
| var drawHandler = Marshal.ReadIntPtr(currentAddr + 0x48); | |
| if (drawHandler == IntPtr.Zero && !getNonDrawables) continue; | |
| var info = new CBuildingWrapped(); | |
| info.Address = currentAddr; | |
| info.Position = (Vector3)Marshal.PtrToStructure(currentAddr + 0x90, typeof(Vector3)); | |
| info.Matrix = (CMatrix)Marshal.PtrToStructure(currentAddr + 0x60, typeof(CMatrix)); | |
| info.ModelName = GetEntityName(currentAddr); | |
| info.ModelHash = info.ModelName.HashKey(); | |
| yield return info; | |
| } | |
| } | |
| public static IEnumerable<CBuildingWrapped> GetCBuildings(Vector3 center, float radius, bool getNonDrawables) | |
| { | |
| var baseAddr = Marshal.ReadIntPtr(_cBuildingPoolPtr); | |
| var itemStart = Marshal.ReadIntPtr(baseAddr); | |
| var count = Marshal.ReadInt32(baseAddr + 0x10); | |
| for (int i = 0; i < count; i++) | |
| { | |
| var currentAddr = itemStart + i * CBuildingClassSize; | |
| var drawHandler = Marshal.ReadIntPtr(currentAddr + 0x48); | |
| if (drawHandler == IntPtr.Zero && !getNonDrawables) continue; | |
| var info = new CBuildingWrapped(); | |
| var matrix = (CMatrix)Marshal.PtrToStructure(currentAddr + 0x60, typeof(CMatrix)); | |
| var position = (Vector3)Marshal.PtrToStructure(currentAddr + 0x90, typeof(Vector3)); | |
| if (center.DistanceToSquared(position) > radius * radius) continue; | |
| info.Address = currentAddr; | |
| info.Matrix = matrix; | |
| info.Position = position; | |
| info.ModelName = GetEntityName(currentAddr); | |
| info.ModelHash = info.ModelName.HashKey(); | |
| yield return info; | |
| } | |
| } | |
| } | |
| } |