Skip to content
Permalink
1364344ddc
Switch branches/tags
Go to file
4 contributors

Users who have contributed to this file

@crosire @sfinktah @kagikn @CamxxCore
1080 lines (944 sloc) 34.5 KB
#include "NativeMemory.hpp"
#include "ScriptDomain.hpp"
#include <Main.h>
#include <Psapi.h>
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Collections::ObjectModel;
using namespace System::Runtime::InteropServices;
const char* const _cellEmailBcon = "CELL_EMAIL_BCON";
const char* const _string = "STRING";
const char* const _nullStr = "";
namespace GTA
{
namespace Native
{
namespace
{
[StructLayout(LayoutKind::Explicit)]
private value class EntityPool
{
public:
[FieldOffset(0x10)]UInt32 num1;
[FieldOffset(0x20)]UInt32 num2;
inline bool Full()
{
return num1 - (num2 & 0x3FFFFFFF) <= 256;
}
};
[StructLayout(LayoutKind::Explicit)]
private value class VehiclePool
{
public:
[FieldOffset(0x00)]UInt64 *poolAddress;
[FieldOffset(0x08)]UInt32 size;
[FieldOffset(0x30)]UInt32* bitArray;
[FieldOffset(0x60)]UInt32 itemCount;
inline bool isValid(UInt32 i)
{
return (bitArray[i >> 5] >> (i & 0x1F)) & 1;
}
inline UInt64 getAddress(UInt32 i)
{
return poolAddress[i];
}
};
[StructLayout(LayoutKind::Explicit)]
private value class GenericPool{
public:
[FieldOffset(0x00)] UInt64 poolStartAddress;
[FieldOffset(0x08)] Byte* byteArray;
[FieldOffset(0x10)] UInt32 size;
[FieldOffset(0x14)] UInt32 itemSize;
inline bool isValid(UInt32 i)
{
return mask(i) != 0;
}
inline UInt64 getAddress(UInt32 i)
{
return mask(i) & (poolStartAddress + i * itemSize);
}
private:
inline long long mask(UInt32 i)
{
long long num1 = byteArray[i] & 0x80;
return ~((num1 | -num1) >> 63);
}
};
private ref struct EntityPoolTask : IScriptTask
{
enum class Type
{
Ped=1,
Object=2,
Vehicle=4,
PickupObject=8
};
EntityPoolTask(Type type) : _type(type) { }
inline bool CheckEntity(uintptr_t address)
{
if (_posCheck)
{
float position[3];
MemoryAccess::_entityPositionFunc(address, position);
if(_position.DistanceToSquared(Math::Vector3(position[0], position[1], position[2])) > _radiusSquared)
{
return false;
}
}
if (_modelCheck)
{
UINT32 v0 = *reinterpret_cast<UINT32 *>(MemoryAccess::_entityModel1Func(*reinterpret_cast<UINT64 *>(address + 32)));
UINT32 v1 = v0 & 0xFFFF;
UINT32 v2 = ((v1 ^ v0) & 0x0FFF0000 ^ v1) & 0xDFFFFFFF;
UINT32 v3 = ((v2 ^ v0) & 0x10000000 ^ v2) & 0x3FFFFFFF;
const uintptr_t v5 = MemoryAccess::_entityModel2Func(reinterpret_cast<uintptr_t>(&v3));
if (!v5)
{
return false;
}
for each(int hash in _modelHashes)
{
if (*reinterpret_cast<int *>(v5 + 24) == hash)
{
return true;
}
}
return false;
}
return true;
}
virtual void Run()
{
if(*MemoryAccess::_entityPoolAddress == 0)
{
return;
}
EntityPool* entityPool = reinterpret_cast<EntityPool*>(*MemoryAccess::_entityPoolAddress);
if(_type.HasFlag(Type::Vehicle))
{
if(*MemoryAccess::_vehiclePoolAddress)
{
VehiclePool* vehiclePool = *reinterpret_cast<VehiclePool**>(*MemoryAccess::_vehiclePoolAddress);
for(UInt32 i = 0; i < vehiclePool->size; i++)
{
if(entityPool->Full())
{
break;
}
if(vehiclePool->isValid(i))
{
UInt64 address = vehiclePool->getAddress(i);
if(address && CheckEntity(address))
{
_handles->Add(MemoryAccess::_addEntityToPoolFunc(address));
}
}
}
}
}
if(_type.HasFlag(Type::Ped))
{
if(*MemoryAccess::_pedPoolAddress)
{
GenericPool* pedPool = reinterpret_cast<GenericPool*>(*MemoryAccess::_pedPoolAddress);
for(UInt32 i = 0; i < pedPool->size; i++)
{
if(entityPool->Full())
{
break;
}
if(pedPool->isValid(i))
{
UInt64 address = pedPool->getAddress(i);
if(address && CheckEntity(address))
{
_handles->Add(MemoryAccess::_addEntityToPoolFunc(address));
}
}
}
}
}
if(_type.HasFlag(Type::Object))
{
if(*MemoryAccess::_objectPoolAddress)
{
GenericPool* propPool = reinterpret_cast<GenericPool*>(*MemoryAccess::_objectPoolAddress);
for(UInt32 i = 0; i < propPool->size; i++)
{
if(entityPool->Full())
{
break;
}
if(propPool->isValid(i))
{
UInt64 address = propPool->getAddress(i);
if(address && CheckEntity(address))
{
_handles->Add(MemoryAccess::_addEntityToPoolFunc(address));
}
}
}
}
}
if(_type.HasFlag(Type::PickupObject))
{
if(*MemoryAccess::_pickupObjectPoolAddress)
{
GenericPool* pickupPool = reinterpret_cast<GenericPool*>(*MemoryAccess::_pickupObjectPoolAddress);
for(UInt32 i = 0; i < pickupPool->size; i++)
{
if(entityPool->Full())
{
break;
}
if(pickupPool->isValid(i))
{
UInt64 address = pickupPool->getAddress(i);
if(address)
{
if (_posCheck)
{
float* position = (float*)(address + 0x90);
if(_position.DistanceToSquared(Math::Vector3(position[0], position[1], position[2])) > _radiusSquared)
{
continue;
}
}
_handles->Add(MemoryAccess::_addEntityToPoolFunc(address));
}
}
}
}
}
}
Type _type;
List<int> ^_handles = gcnew List<int>();
bool _posCheck, _modelCheck;
Math::Vector3 _position;
float _radiusSquared;
array<int> ^_modelHashes;
};
private ref struct EuphoriaMessageTask : IScriptTask
{
EuphoriaMessageTask(int target, String ^message, Dictionary<String ^, Object ^> ^arguments) : _targetHandle(target), _message(message), _arguments(arguments) { }
virtual void Run()
{
__int64 NativeFunc = Native::MemoryAccess::CreateNmMessageFunc;
__int64 MessageAddress = reinterpret_cast<__int64(*)(__int64)>(*reinterpret_cast<int*>(NativeFunc + 0x22) + NativeFunc + 0x26)(4632);
if (MessageAddress == 0)
{
return;
}
reinterpret_cast<__int64(*)(__int64, __int64, int)>(*reinterpret_cast<int*>(NativeFunc + 0x3C) + NativeFunc + 0x40)(MessageAddress, MessageAddress + 24, 64);
for each (auto argument in _arguments)
{
IntPtr name = ScriptDomain::CurrentDomain->PinString(argument.Key);
if (argument.Value->GetType() == Boolean::typeid)
{
MemoryAccess::SetNmBoolAddress(MessageAddress, name.ToInt64(), (bool)argument.Value ? 1 : 0);
}
if (argument.Value->GetType() == Int32::typeid)
{
MemoryAccess::SetNmIntAddress(MessageAddress, name.ToInt64(), (int)argument.Value);
}
if (argument.Value->GetType() == Single::typeid)
{
MemoryAccess::SetNmFloatAddress(MessageAddress, name.ToInt64(), (float)argument.Value);
}
if (argument.Value->GetType() == Math::Vector3::typeid)
{
auto value = (Math::Vector3)argument.Value;
MemoryAccess::SetNmVec3Address(MessageAddress, name.ToInt64(), value.X, value.Y, value.Z);
}
if (argument.Value->GetType() == String::typeid)
{
MemoryAccess::SetNmStringAddress(MessageAddress, name.ToInt64(), ScriptDomain::CurrentDomain->PinString((String ^)argument.Value).ToInt64());
}
}
__int64 BaseFunc = Native::MemoryAccess::GiveNmMessageFunc;
__int64 ByteAddr = *reinterpret_cast<int*>(BaseFunc + 0xBC) + BaseFunc + 0xC0;
__int64 UnkStrAddr = *reinterpret_cast<int*>(BaseFunc + 0xCE) + BaseFunc + 0xD2;
__int64 _PedAddress = Native::MemoryAccess::GetEntityAddress(_targetHandle).ToInt64();
__int64 PedNmAddress;
bool v5 = false;
__int8 v7;
__int64 v11;
__int64 v12;
if (_PedAddress == 0)
return;
if (*reinterpret_cast<__int64*>(_PedAddress + 48) == 0)
return;
int AddrOff = getGameVersion() < VER_1_0_573_1_NOSTEAM ? 0 : 16;
PedNmAddress = *reinterpret_cast<__int64*>(_PedAddress + 5016 + AddrOff); //
if (*reinterpret_cast<__int64*>(_PedAddress + 48) == PedNmAddress && *reinterpret_cast<float*>(_PedAddress + 5232 + AddrOff) <= *reinterpret_cast<float*>(_PedAddress + 640))
{
if ((*reinterpret_cast<int(**)(__int64)> (*reinterpret_cast<__int64*>(PedNmAddress) + 152))(PedNmAddress) != -1)
{
if (*(short *)(reinterpret_cast<__int64(*)(__int64)>(*reinterpret_cast<int*>(BaseFunc + 0xA2) + BaseFunc + 0xA6)(*(__int64 *)(*(__int64 *)(_PedAddress + 4208 + AddrOff) + 864)) + 52) == 401)
{
v5 = true;
}
else
{
v7 = *(__int8*)ByteAddr;
if (v7)
{
reinterpret_cast<void(*)(__int64)>(*reinterpret_cast<int*>(BaseFunc + 0xD3) + BaseFunc + 0xD7)(UnkStrAddr);
v7 = *(__int8*)ByteAddr;
}
int count = *reinterpret_cast<int*>(*reinterpret_cast<__int64*>(_PedAddress + 4208 + AddrOff) + 1064);
if (v7)
{
reinterpret_cast<void(*)(__int64)>(*reinterpret_cast<int*>(BaseFunc + 0xF0) + BaseFunc + 0xF4)(UnkStrAddr);
}
for (int i = 0; i < count; i++)
{
v11 = *reinterpret_cast<__int64*>(*reinterpret_cast<__int64*>(_PedAddress + 4208 + AddrOff) + 8 * ((i + *reinterpret_cast<int*>(*reinterpret_cast<__int64*>(_PedAddress + 4208 + AddrOff) + 1060) + 1) % 16) + 928);
if (v11)
{
if ((*(int(__fastcall **)(__int64))(*reinterpret_cast<__int64*>(v11) + 24))(v11) == 132)
{
v12 = *reinterpret_cast<__int64*>(v11 + 40);
if (v12)
{
if (*reinterpret_cast<short*>(v12 + 52) == 401)
v5 = true;
}
}
}
}
}
if (v5 && (*reinterpret_cast<int(**)(__int64)>(*reinterpret_cast<__int64*>(PedNmAddress) + 152))(PedNmAddress) != -1)
{
reinterpret_cast<void(*)(__int64, __int64, __int64)>(*reinterpret_cast<int*>(BaseFunc + 0x1AA) + BaseFunc + 0x1AE)(PedNmAddress, ScriptDomain::CurrentDomain->PinString(_message).ToInt64(), MessageAddress);//Send Message To Ped
}
reinterpret_cast<void(*)(__int64)>(*reinterpret_cast<int*>(BaseFunc + 0x1BB) + BaseFunc + 0x1BF)(MessageAddress);//Free Message Memory
}
}
}
int _targetHandle;
String ^_message;
Dictionary<String ^, Object ^> ^_arguments;
};
private ref struct GenericTask : IScriptTask
{
public:
typedef UInt64(*func)(UInt64);
GenericTask(func pFunc, UInt64 Arg) : _toRun(pFunc), _arg(Arg)
{
}
virtual void Run()
{
_res = _toRun(_arg);
}
UInt64 GetResult()
{
return _res;
}
private:
func _toRun;
UInt64 _arg;
UInt64 _res;
};
}
static MemoryAccess::MemoryAccess()
{
uintptr_t address;
// Get relative address and add it to the instruction address.
// 3 bytes equal the size of the opcode and its first argument. 7 bytes are the length of opcode and all its parameters.
address = FindPattern("\x33\xFF\xE8\x00\x00\x00\x00\x48\x85\xC0\x74\x58", "xxx????xxxxx");
_entityAddressFunc = reinterpret_cast<uintptr_t(*)(int)>(*reinterpret_cast<int *>(address + 3) + address + 7);
address = FindPattern("\xB2\x01\xE8\x00\x00\x00\x00\x33\xC9\x48\x85\xC0\x74\x3B", "xxx????xxxxxxx");
_playerAddressFunc = reinterpret_cast<uintptr_t(*)(int)>(*reinterpret_cast<int *>(address + 3) + address + 7);
address = FindPattern("\x74\x21\x48\x8B\x48\x20\x48\x85\xC9\x74\x18\x48\x8B\xD6\xE8", "xxxxxxxxxxxxxxx") - 10;
_ptfxAddressFunc = reinterpret_cast<uintptr_t(*)(int)>(*reinterpret_cast<int*>(address) + address + 4);
address = FindPattern("\x48\xF7\xF9\x49\x8B\x48\x08\x48\x63\xD0\xC1\xE0\x08\x0F\xB6\x1C\x11\x03\xD8", "xxxxxxxxxxxxxxxxxxx");
_addEntityToPoolFunc = reinterpret_cast<int(*)(uintptr_t)>(address - 0x68);
address = FindPattern("\x48\x8B\xC8\xE8\x00\x00\x00\x00\xF3\x0F\x10\x54\x24\x00\xF3\x0F\x10\x4C\x24\x00\xF3\x0F\x10", "xxxx????xxxxx?xxxxx?xxx");
_entityPositionFunc = reinterpret_cast<UINT64(*)(UINT64, float *)>(*reinterpret_cast<int *>(address + 4) + address + 8);
address = FindPattern("\x25\xFF\xFF\xFF\x3F\x89\x44\x24\x38\xE8\x00\x00\x00\x00\x48\x85\xC0\x74\x03", "xxxxxxxxxx????xxxxx");
_entityModel1Func = reinterpret_cast<UINT64(*)(UINT64)>(*reinterpret_cast<int *>(address - 61) + address - 57);
_entityModel2Func = reinterpret_cast<UINT64(*)(UINT64)>(*reinterpret_cast<int *>(address + 10) + address + 14);
address = FindPattern("\x4C\x8B\x0D\x00\x00\x00\x00\x44\x8B\xC1\x49\x8B\x41\x08", "xxx????xxxxxxx");
_entityPoolAddress = reinterpret_cast<uintptr_t *>(*reinterpret_cast<int *>(address + 3) + address + 7);
address = FindPattern("\x48\x8B\x05\x00\x00\x00\x00\xF3\x0F\x59\xF6\x48\x8B\x08", "xxx????xxxxxxx");
_vehiclePoolAddress = reinterpret_cast<uintptr_t *>(*reinterpret_cast<int *>(address + 3) + address + 7);
address = FindPattern("\x48\x8B\x05\x00\x00\x00\x00\x41\x0F\xBF\xC8\x0F\xBF\x40\x10", "xxx????xxxxxxxx");
_pedPoolAddress = reinterpret_cast<uintptr_t *>(*reinterpret_cast<int *>(address + 3) + address + 7);
address = FindPattern("\x48\x8B\x05\x00\x00\x00\x00\x8B\x78\x10\x85\xFF", "xxx????xxxxx");
_objectPoolAddress = reinterpret_cast<uintptr_t *>(*reinterpret_cast<int *>(address + 3) + address + 7);
address = FindPattern("\x8B\xF0\x48\x8B\x05\x00\x00\x00\x00\xF3\x0F\x59\xF6", "xxxxx????xxxx");
_pickupObjectPoolAddress = reinterpret_cast<uintptr_t *>(*reinterpret_cast<int *>(address + 5) + address + 9);
CreateNmMessageFunc = FindPattern("\x33\xDB\x48\x89\x1D\x00\x00\x00\x00\x85\xFF", "xxxxx????xx") - 0x42;
GiveNmMessageFunc = FindPattern("\x48\x8b\xc4\x48\x89\x58\x08\x48\x89\x68\x10\x48\x89\x70\x18\x48\x89\x78\x20\x41\x55\x41\x56\x41\x57\x48\x83\xec\x20\xe8\x00\x00\x00\x00\x48\x8b\xd8\x48\x85\xc0\x0f", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx????xxxxxxx");
address = FindPattern("\x48\x89\x5C\x24\x00\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x63\x49\x0C\x41\x8A\xF8", "xxxx?xxxxxxxxxxxxxxx");
SetNmBoolAddress = reinterpret_cast<unsigned char(*)(__int64, __int64, unsigned char)>(address);
address = FindPattern("\x40\x53\x48\x83\xEC\x30\x48\x8B\xD9\x48\x63\x49\x0C", "xxxxxxxxxxxxx");
SetNmFloatAddress = reinterpret_cast<unsigned char(*)(__int64, __int64, float)>(address);
address = FindPattern("\x48\x89\x5C\x24\x00\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x63\x49\x0C\x41\x8B\xF8", "xxxx?xxxxxxxxxxxxxxx");
SetNmIntAddress = reinterpret_cast<unsigned char(*)(__int64, __int64, int)>(address);
address = FindPattern("\x57\x48\x83\xEC\x20\x48\x8B\xD9\x48\x63\x49\x0C\x49\x8B\xE8", "xxxxxxxxxxxxxxx") - 15;
SetNmStringAddress = reinterpret_cast<unsigned char(*)(__int64, __int64, __int64)>(address);
address = FindPattern("\x40\x53\x48\x83\xEC\x40\x48\x8B\xD9\x48\x63\x49\x0C", "xxxxxxxxxxxxx");
SetNmVec3Address = reinterpret_cast<unsigned char(*)(__int64, __int64, float, float, float)>(address);
address = FindPattern("\x8A\x4C\x24\x60\x8B\x50\x10\x44\x8A\xCE", "xxxxxxxxxx");
CheckpointBaseAddr = reinterpret_cast<UINT64(*)()>(*reinterpret_cast<int*>(address - 19) + address - 15);
CheckpointHandleAddr = reinterpret_cast<UINT64(*)(UINT64, int)>(*reinterpret_cast<int*>(address - 9) + address - 5);
checkpointPoolAddress = reinterpret_cast<uintptr_t *>(*reinterpret_cast<int *>(address + 17) + address + 21);
address = FindPattern("\x48\x8B\x0B\x33\xD2\xE8\x00\x00\x00\x00\x89\x03", "xxxxxx????xx");
_getHashKey = reinterpret_cast<unsigned int(*)(char*, unsigned int)>(*reinterpret_cast<int*>(address + 6) + address + 10);
address = FindPattern("\x48\x63\xC1\x48\x8D\x0D\x00\x00\x00\x00\xF3\x0F\x10\x04\x81\xF3\x0F\x11\x05\x00\x00\x00\x00", "xxxxxx????xxxxxxxxx????");
_writeWorldGravityAddr = reinterpret_cast<float *>(*reinterpret_cast<int *>(address + 6) + address + 10);
_readWorldGravityAddr = reinterpret_cast<float *>(*reinterpret_cast<int *>(address + 19) + address + 23);
address = FindPattern("\x74\x11\x8B\xD1\x48\x8D\x0D\x00\x00\x00\x00\x45\x33\xC0", "xxxxxxx????xxx");
_cursorSpriteAddr = reinterpret_cast<int *>(*reinterpret_cast<int*>(address - 4) + address);
address = FindPattern("\x48\x8B\xC7\xF3\x0F\x10\x0D", "xxxxxxx") - 0x1D;
address = address + *reinterpret_cast<int*>(address) + 4;
_gamePlayCameraAddr = reinterpret_cast<UInt64*>(*reinterpret_cast<int*>(address + 3) + address + 7);
address = FindPattern("\x48\x8B\xC8\xEB\x02\x33\xC9\x48\x85\xC9\x74\x26", "xxxxxxxxxxxx") - 9;
_cameraPoolAddress = reinterpret_cast<UInt64*>(*reinterpret_cast<int*>(address) + address + 4);
GenerateVehicleModelList();
_cellEmailBconPtr = IntPtr((void*)_cellEmailBcon);
_stringPtr = IntPtr((void*)_string);
_nullString = IntPtr((void*)_nullStr);
}
IntPtr MemoryAccess::CellEmailBcon::get()
{
return _cellEmailBconPtr;
}
IntPtr MemoryAccess::StringPtr::get()
{
return _stringPtr;
}
IntPtr MemoryAccess::NullString::get()
{
return _nullString;
}
struct HashNode
{
int hash;
UINT16 data;
UINT16 padding;
HashNode* next;
};
inline bool bittest(int data, unsigned char index)
{
return (data & (1 << index)) != 0;
}
void MemoryAccess::GenerateVehicleModelList()
{
uintptr_t address = FindPattern("\x66\x81\xF9\x00\x00\x74\x10\x4D\x85\xC0", "xxx??xxxxx") - 0x21;
UINT64 baseFuncAddr = address + *reinterpret_cast<int*>(address)+4;
modelHashEntries = *reinterpret_cast<PUINT16>(baseFuncAddr + *reinterpret_cast<int*>(baseFuncAddr + 3) + 7);
modelNum1 = *reinterpret_cast<int*>(*reinterpret_cast<int*>(baseFuncAddr + 0x52) + baseFuncAddr + 0x56);
modelNum2 = *reinterpret_cast<PUINT64>(*reinterpret_cast<int*>(baseFuncAddr + 0x63) + baseFuncAddr + 0x67);
modelNum3 = *reinterpret_cast<PUINT64>(*reinterpret_cast<int*>(baseFuncAddr + 0x7A) + baseFuncAddr + 0x7E);
modelNum4 = *reinterpret_cast<PUINT64>(*reinterpret_cast<int*>(baseFuncAddr + 0x81) + baseFuncAddr + 0x85);
modelHashTable = *reinterpret_cast<PUINT64>(*reinterpret_cast<int*>(baseFuncAddr + 0x24) + baseFuncAddr + 0x28);
int vehClassOff = *reinterpret_cast<int*>(address + 0x31);
HashNode** HashMap = reinterpret_cast<HashNode**>(modelHashTable);
array<List<int>^> ^hashes = gcnew array<List<int>^>(0x20);
for (int i = 0; i<0x20; i++)
{
hashes[i] = gcnew List<int>();
}
for (int i = 0; i < modelHashEntries; i++)
{
for (HashNode* cur = HashMap[i]; cur; cur = cur->next)
{
UINT16 data = cur->data;
if ((int)data < modelNum1 && bittest(*reinterpret_cast<int*>(modelNum2 + (4 * data >> 5)), data & 0x1F))
{
UINT64 addr1 = modelNum4 + modelNum3 * data;
if (addr1)
{
UINT64 addr2 = *reinterpret_cast<PUINT64>(addr1);
if (addr2)
{
if ((*reinterpret_cast<PBYTE>(addr2 + 157) & 0x1F) == 5)
{
hashes[*reinterpret_cast<PBYTE>(addr2 + vehClassOff) & 0x1F]->Add(cur->hash);
}
}
}
}
}
}
array<ReadOnlyCollection<int> ^> ^result = gcnew array<ReadOnlyCollection<int> ^>(0x20);
for (int i = 0; i<0x20; i++)
{
result[i] = Array::AsReadOnly(hashes[i]->ToArray());
}
vehicleModels = Array::AsReadOnly(result);
}
bool MemoryAccess::IsModelAPed(int modelHash)
{
HashNode** HashMap = reinterpret_cast<HashNode**>(modelHashTable);
for (HashNode* cur = HashMap[static_cast<unsigned int>(modelHash) % modelHashEntries]; cur; cur = cur->next)
{
if (cur->hash != modelHash)
{
continue;
}
UINT16 data = cur->data;
if ((int)data < modelNum1 && bittest(*reinterpret_cast<int*>(modelNum2 + (4 * data >> 5)), data & 0x1F))
{
UINT64 addr1 = modelNum4 + modelNum3 * data;
if (addr1)
{
UINT64 addr2 = *reinterpret_cast<PUINT64>(addr1);
if (addr2)
{
return (*reinterpret_cast<PBYTE>(addr2 + 157) & 0x1F) == 6;
}
}
}
}
return false;
}
int MemoryAccess::GetGameVersion()
{
return getGameVersion();
}
char MemoryAccess::ReadSByte(IntPtr address)
{
const auto data = static_cast<const char *>(address.ToPointer());
return *data;
}
unsigned char MemoryAccess::ReadByte(IntPtr address)
{
const auto data = static_cast<const unsigned char *>(address.ToPointer());
return *data;
}
short MemoryAccess::ReadShort(IntPtr address)
{
const auto data = static_cast<const short *>(address.ToPointer());
return *data;
}
unsigned short MemoryAccess::ReadUShort(IntPtr address)
{
const auto data = static_cast<const unsigned short *>(address.ToPointer());
return *data;
}
int MemoryAccess::ReadInt(IntPtr address)
{
const auto data = static_cast<const int *>(address.ToPointer());
return *data;
}
unsigned int MemoryAccess::ReadUInt(IntPtr address)
{
const auto data = static_cast<const unsigned int *>(address.ToPointer());
return *data;
}
float MemoryAccess::ReadFloat(IntPtr address)
{
const auto data = static_cast<const float *>(address.ToPointer());
return *data;
}
Math::Vector3 MemoryAccess::ReadVector3(IntPtr address)
{
const auto data = static_cast<const float *>(address.ToPointer());
return Math::Vector3(data[0], data[1], data[2]);
}
String ^MemoryAccess::ReadString(IntPtr address)
{
const auto data = static_cast<const char *>(address.ToPointer());
return gcnew System::String(data);
}
IntPtr MemoryAccess::ReadPtr(IntPtr address)
{
const auto data = static_cast<void **>(address.ToPointer());
return IntPtr(*data);
}
Math::Matrix MemoryAccess::ReadMatrix(System::IntPtr address)
{
const auto data = static_cast<const Math::Matrix*>(address.ToPointer());
return Math::Matrix(*data);
}
long long MemoryAccess::ReadLong(IntPtr address)
{
const auto data = static_cast<const long long *>(address.ToPointer());
return *data;
}
unsigned long long MemoryAccess::ReadULong(IntPtr address)
{
const auto data = static_cast<const unsigned long long *>(address.ToPointer());
return *data;
}
void MemoryAccess::WriteSByte(System::IntPtr address, char value)
{
const auto data = static_cast<char *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteByte(System::IntPtr address, unsigned char value)
{
const auto data = static_cast<unsigned char *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteShort(System::IntPtr address, short value)
{
const auto data = static_cast<short *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteUShort(System::IntPtr address, unsigned short value)
{
const auto data = static_cast<unsigned short *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteInt(IntPtr address, int value)
{
const auto data = static_cast<int *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteUInt(IntPtr address, unsigned int value)
{
const auto data = static_cast<unsigned int *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteFloat(IntPtr address, float value)
{
const auto data = static_cast<float *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteVector3(IntPtr address, Math::Vector3 value)
{
const auto data = static_cast<float *>(address.ToPointer());
data[0] = value.X;
data[1] = value.Y;
data[2] = value.Z;
}
void MemoryAccess::WriteMatrix(IntPtr address, Math::Matrix value)
{
const auto data = static_cast<float *>(address.ToPointer());
auto arr = value.ToArray();
for (int i = 0; i < arr->Length; i++)
{
data[i] = arr[i];
}
}
void MemoryAccess::WriteLong(IntPtr address, long long value)
{
const auto data = static_cast<long long *>(address.ToPointer());
*data = value;
}
void MemoryAccess::WriteULong(IntPtr address, unsigned long long value)
{
const auto data = static_cast<unsigned long long *>(address.ToPointer());
*data = value;
}
void MemoryAccess::SetBit(IntPtr address, int bit)
{
if (bit < 0 || bit >31)
{
throw gcnew ArgumentOutOfRangeException("bit", "The bit index has to be between 0 and 31");
}
const int mask = 1 << bit;
const auto data = static_cast<int *>(address.ToPointer());
*data |= mask;
}
void MemoryAccess::ClearBit(IntPtr address, int bit)
{
if (bit < 0 || bit >31)
{
throw gcnew ArgumentOutOfRangeException("bit", "The bit index has to be between 0 and 31");
}
const int mask = 1 << bit;
const auto data = static_cast<int *>(address.ToPointer());
*data &= ~mask;
}
bool MemoryAccess::IsBitSet(IntPtr address, int bit)
{
if (bit < 0 || bit >31)
{
throw gcnew ArgumentOutOfRangeException("bit", "The bit index has to be between 0 and 31");
}
const int mask = 1 << bit;
const auto data = static_cast<int *>(address.ToPointer());
return (*data & mask) != 0;
}
unsigned int MemoryAccess::GetHashKey(String^ toHash)
{
IntPtr handle = ScriptDomain::CurrentDomain->PinString(toHash);
return _getHashKey((char*)handle.ToPointer(), 0);
}
IntPtr MemoryAccess::GetEntityAddress(int handle)
{
return IntPtr((long long)_entityAddressFunc(handle));
}
IntPtr MemoryAccess::GetPlayerAddress(int handle)
{
return IntPtr((long long)_playerAddressFunc(handle));
}
UInt64 _getCheckpointAddress(UInt64 Data)
{
int handle = *(int*)(&Data);
UInt64 addr = MemoryAccess::CheckpointHandleAddr(MemoryAccess::CheckpointBaseAddr(), handle);
if (addr != 0)
{
return (UInt64)((UInt64)(MemoryAccess::checkpointPoolAddress) + 96 * *reinterpret_cast<int *>(addr + 16));
}
return 0;
}
IntPtr MemoryAccess::GetCheckpointAddress(int handle)
{
GenericTask ^task = gcnew GenericTask(_getCheckpointAddress, handle);
ScriptDomain::CurrentDomain->ExecuteTask(task);
return IntPtr((long long)task->GetResult());
}
IntPtr MemoryAccess::GetPtfxAddress(int handle)
{
return IntPtr((long long)_ptfxAddressFunc(handle));
}
int MemoryAccess::GetEntityBoneCount(int handle)
{
auto fragSkeletonData = GetEntitySkeletonData(handle);
return fragSkeletonData ? *reinterpret_cast<int*>(fragSkeletonData + 32) : 0;
}
IntPtr MemoryAccess::GetEntityBoneMatrixAddress(int handle, int boneIndex)
{
if ((boneIndex & 0x80000000) != 0)//boneIndex cant be negative
return IntPtr::Zero;
auto fragSkeletonData = GetEntitySkeletonData(handle);
if (!fragSkeletonData) return IntPtr::Zero;
if (boneIndex < *reinterpret_cast<int*>(fragSkeletonData + 32))// boneIndex < max bones?
{
return IntPtr((long long)(*(UInt64*)(fragSkeletonData + 24) + (boneIndex * 0x40)));
}
return IntPtr::Zero;
}
IntPtr MemoryAccess::GetEntityBonePoseAddress(int handle, int boneIndex)
{
if ((boneIndex & 0x80000000) != 0)//boneIndex cant be negative
return IntPtr::Zero;
auto fragSkeletonData = GetEntitySkeletonData(handle);
if (!fragSkeletonData) return IntPtr::Zero;
if (boneIndex < *reinterpret_cast<int*>(fragSkeletonData + 32))// boneIndex < max bones?
{
return IntPtr((long long)(*(UInt64*)(fragSkeletonData + 16) + (boneIndex * 0x40)));
}
return IntPtr::Zero;
}
unsigned long long MemoryAccess::GetEntitySkeletonData(int handle)
{
UInt64 MemAddress = _entityAddressFunc(handle);
UInt64 Addr2 = (*(UInt64(__thiscall **)(__int64))(*(UInt64 *)MemAddress + 88i64))(MemAddress);
UInt64 Addr3;
if (!Addr2)
{
Addr3 = *(UInt64*)(MemAddress + 80);
if (!Addr3)
{
return 0;
}
else
{
Addr3 = *(UInt64*)(Addr3 + 40);
}
}
else
{
Addr3 = *(UInt64*)(Addr2 + 104);
if (!Addr3 || !*(UInt64*)(Addr2 + 120))
{
return 0;
}
else
{
Addr3 = *(UInt64*)(Addr3 + 376);
}
}
if (!Addr3)
{
return 0;
}
return Addr3;
}
float MemoryAccess::ReadWorldGravity()
{
return *_readWorldGravityAddr;
}
void MemoryAccess::WriteWorldGravity(float value)
{
*_writeWorldGravityAddr = value;
}
int MemoryAccess::ReadCursorSprite()
{
return *_cursorSpriteAddr;
}
IntPtr MemoryAccess::GetGameplayCameraAddress()
{
return IntPtr((long long)*_gamePlayCameraAddr);
}
IntPtr MemoryAccess::GetCameraAddress(int handle)
{
unsigned int index = (unsigned int)(handle >> 8);
UInt64 poolAddr = *_cameraPoolAddress;
if(*(Byte *)(index + *(Int64*)(poolAddr + 8)) == (Byte)(handle & 0xFF))
{
return IntPtr(*(Int64*)poolAddr + (unsigned int)(index * *(UInt32 *)(poolAddr + 20)));
}
return IntPtr::Zero;
}
array<int> ^MemoryAccess::GetEntityHandles()
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Ped | EntityPoolTask::Type::Object | EntityPoolTask::Type::Vehicle);
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetEntityHandles(Math::Vector3 position, float radius)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Ped | EntityPoolTask::Type::Object | EntityPoolTask::Type::Vehicle);
task->_position = position;
task->_radiusSquared = radius * radius;
task->_posCheck = true;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetVehicleHandles(array<int> ^modelhashes)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Vehicle);
task->_modelHashes = modelhashes;
task->_modelCheck = modelhashes != nullptr && modelhashes->Length > 0;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetVehicleHandles(Math::Vector3 position, float radius, array<int> ^modelhashes)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Vehicle);
task->_position = position;
task->_radiusSquared = radius * radius;
task->_posCheck = true;
task->_modelHashes = modelhashes;
task->_modelCheck = modelhashes != nullptr && modelhashes->Length > 0;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetPedHandles(array<int> ^modelhashes)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Ped);
task->_modelHashes = modelhashes;
task->_modelCheck = modelhashes != nullptr && modelhashes->Length > 0;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetPedHandles(Math::Vector3 position, float radius, array<int> ^modelhashes)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Ped);
task->_position = position;
task->_radiusSquared = radius * radius;
task->_posCheck = true;
task->_modelHashes = modelhashes;
task->_modelCheck = modelhashes != nullptr && modelhashes->Length > 0;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetPropHandles(array<int> ^modelhashes)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Object);
task->_modelHashes = modelhashes;
task->_modelCheck = modelhashes != nullptr && modelhashes->Length > 0;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetPropHandles(Math::Vector3 position, float radius, array<int> ^modelhashes)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::Object);
task->_position = position;
task->_radiusSquared = radius * radius;
task->_posCheck = true;
task->_modelHashes = modelhashes;
task->_modelCheck = modelhashes != nullptr && modelhashes->Length > 0;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
struct checkpoint
{
char padding[0xC];
int handle;
char padding1[0x08];
checkpoint* next;
};
UInt64 _getCheckpoinHandles(UInt64 ArrayPtr)
{
int* handles = (int*)ArrayPtr;
UInt64 count = 0;
for (checkpoint* item = *reinterpret_cast<checkpoint**>(MemoryAccess::CheckpointBaseAddr() + 48); item && count < 64; item = item->next)
{
handles[count++] = item->handle;
}
return count;
}
array<int> ^MemoryAccess::GetCheckpointHandles()
{
int Handles[64];
GenericTask ^task = gcnew GenericTask(_getCheckpoinHandles, (UInt64)Handles);
ScriptDomain::CurrentDomain->ExecuteTask(task);
int count = (int)task->GetResult();
array<int>^ data_array = gcnew array<int>(count);
pin_ptr<int> ptrBuffer = &data_array[0];
memcpy(ptrBuffer, Handles, count * 4);
return data_array;
}
array<int> ^MemoryAccess::GetPickupObjectHandles()
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::PickupObject);
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
array<int> ^MemoryAccess::GetPickupObjectHandles(Math::Vector3 position, float radius)
{
auto task = gcnew EntityPoolTask(EntityPoolTask::Type::PickupObject);
task->_position = position;
task->_radiusSquared = radius * radius;
task->_posCheck = true;
ScriptDomain::CurrentDomain->ExecuteTask(task);
return task->_handles->ToArray();
}
int MemoryAccess::GetNumberOfVehicles()
{
if (*_vehiclePoolAddress)
{
VehiclePool* pool = *reinterpret_cast<VehiclePool**>(*_vehiclePoolAddress);
return pool->itemCount;
}
return 0;
}
void MemoryAccess::SendEuphoriaMessage(int targetHandle, String ^message, Dictionary<String ^, Object ^> ^arguments)
{
auto task = gcnew EuphoriaMessageTask(targetHandle, message, arguments);
ScriptDomain::CurrentDomain->ExecuteTask(task);
}
int MemoryAccess::CreateTexture(System::String ^filename)
{
return createTexture(static_cast<const char *>(ScriptDomain::CurrentDomain->PinString(filename).ToPointer()));
}
void MemoryAccess::DrawTexture(int id, int index, int level, int time, float sizeX, float sizeY, float centerX, float centerY, float posX, float posY, float rotation, float scaleFactor, Drawing::Color color)
{
drawTexture(id, index, level, time, sizeX, sizeY, centerX, centerY, posX, posY, rotation, scaleFactor, color.R / 255.0f, color.G / 255.0f, color.B / 255.0f, color.A / 255.0f);
}
uintptr_t MemoryAccess::FindPattern(const char *pattern, const char *mask)
{
MODULEINFO module = { };
GetModuleInformation(GetCurrentProcess(), GetModuleHandle(nullptr), &module, sizeof(MODULEINFO));
auto *address = reinterpret_cast<const char *>(module.lpBaseOfDll), *address_end = address + module.SizeOfImage;
const auto mask_length = static_cast<size_t>(strlen(mask) - 1);
for (size_t i = 0; address < address_end; address++)
{
if (*address == pattern[i] || mask[i] == '?')
{
if (mask[i + 1] == '\0')
{
return reinterpret_cast<uintptr_t>(address) - mask_length;
}
i++;
}
else
{
i = 0;
}
}
return 0;
}
}
}