Added local caching for peds, vehicles and weapons (#457)
This commit is contained in:
parent
04aad64439
commit
7f25ee41cc
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -22,3 +22,7 @@
|
||||
path = vendor/ImGui
|
||||
url = https://github.com/Yimura/gtav-imgui.git
|
||||
ignore = dirty
|
||||
[submodule "vendor/pugixml"]
|
||||
path = vendor/pugixml
|
||||
url = https://github.com/zeux/pugixml.git
|
||||
ignore = dirty
|
@ -53,4 +53,10 @@ namespace big::functions
|
||||
//Sync signatures END
|
||||
|
||||
using reset_network_complaints = void(*)(CNetComplaintMgr* mgr);
|
||||
}
|
||||
|
||||
using fidevice_get_device = rage::fiDevice*(*)(const char* path, bool allow_root);
|
||||
using fipackfile_ctor = rage::fiPackfile*(*)(rage::fiPackfile* this_);
|
||||
using fipackfile_open_archive = bool(*)(rage::fiPackfile* this_, const char* archive, bool b_true, int type, intptr_t very_false);
|
||||
using fipackfile_mount = bool(*)(rage::fiPackfile* this_, const char* mount_point);
|
||||
using fipackfile_unmount = bool(*)(const char* mount_point);
|
||||
}
|
||||
|
263
BigBaseV2/src/gta/fidevice.cpp
Normal file
263
BigBaseV2/src/gta/fidevice.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
#include "fidevice.hpp"
|
||||
#include "pointers.hpp"
|
||||
|
||||
namespace rage
|
||||
{
|
||||
#define PURECALL() LOG(FATAL) << "pure fiDevice call (" __FUNCTION__ ")"; return 0
|
||||
|
||||
fiDeviceImplemented::fiDeviceImplemented()
|
||||
{
|
||||
}
|
||||
|
||||
fiDeviceImplemented::~fiDeviceImplemented()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
fiDevice::~fiDevice()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::Open(const char* fileName, bool) { PURECALL(); }
|
||||
|
||||
uint64_t fiDeviceImplemented::OpenBulk(const char* fileName, uint64_t* ptr)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::OpenBulkWrap(const char* fileName, uint64_t* ptr, void* a3)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::CreateLocal(const char* fileName)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::Create(const char*)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint32_t fiDeviceImplemented::Read(uint64_t handle, void* buffer, uint32_t toRead)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint32_t fiDeviceImplemented::ReadBulk(uint64_t handle, uint64_t ptr, void* buffer, uint32_t toRead)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint32_t fiDeviceImplemented::WriteBulk(uint64_t, int, int, int, int)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint32_t fiDeviceImplemented::Write(uint64_t, void*, int)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint32_t fiDeviceImplemented::Seek(uint64_t handle, int32_t distance, uint32_t method)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::SeekLong(uint64_t handle, int64_t distance, uint32_t method)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int32_t fiDeviceImplemented::Close(uint64_t handle)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int32_t fiDeviceImplemented::CloseBulk(uint64_t handle)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::GetFileLength(uint64_t handle)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::m_40(int)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::RemoveFile(const char* file)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::RenameFile(const char* from, const char* to)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::CreateDirectory(const char* dir)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::RemoveDirectory(const char* dir)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::GetFileLengthUInt64(uint64_t file)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::GetFileLengthLong(const char* fileName)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::GetFileTime(const char* file)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::SetFileTime(const char* file, FILETIME fileTime)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint64_t fiDeviceImplemented::FindFirst(const char* path, fiFindData* findData)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::FindNext(uint64_t handle, fiFindData* findData)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::FindClose(uint64_t handle)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
rage::fiDevice* fiDeviceImplemented::GetUnkDevice()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
void* fiDeviceImplemented::m_xy(void* a1, int a2, void* a3)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::Truncate(uint64_t handle)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
uint32_t fiDeviceImplemented::GetFileAttributes(const char* path)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::m_xz()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::SetFileAttributes(const char* file, uint32_t FileAttributes)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
void fiDeviceImplemented::m_xx()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::ReadFull(uint64_t handle, void* buffer, uint32_t length)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::WriteFull(uint64_t handle, void* buffer, uint32_t length)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int32_t fiDeviceImplemented::GetResourceVersion(const char* fileName, ResourceFlags* flags)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::m_yx()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::m_yy()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::m_yz(void*)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::m_zx(void*)
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::IsCollection()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::m_addedIn1290()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
fiDevice* fiDeviceImplemented::GetCollection()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
bool fiDeviceImplemented::m_ax()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
int fiDeviceImplemented::GetCollectionId()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
const char* fiDeviceImplemented::GetName()
|
||||
{
|
||||
PURECALL();
|
||||
}
|
||||
|
||||
fiPackfile::fiPackfile()
|
||||
{
|
||||
big::g_pointers->m_fipackfile_ctor(this);
|
||||
}
|
||||
|
||||
bool fiPackfile::OpenPackfile(const char* archive, bool b_true, int type, intptr_t very_false)
|
||||
{
|
||||
return big::g_pointers->m_fipackfile_open_archive(this, archive, b_true, type, very_false);
|
||||
}
|
||||
|
||||
bool fiPackfile::Mount(const char* mount_point)
|
||||
{
|
||||
return big::g_pointers->m_fipackfile_mount(this, mount_point);
|
||||
}
|
||||
}
|
286
BigBaseV2/src/gta/fidevice.hpp
Normal file
286
BigBaseV2/src/gta/fidevice.hpp
Normal file
@ -0,0 +1,286 @@
|
||||
#pragma once
|
||||
|
||||
#include "sysMemAllocator.hpp"
|
||||
#include "pointers.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace rage
|
||||
{
|
||||
struct fiFindData
|
||||
{
|
||||
char fileName[256];
|
||||
uint64_t fileSize;
|
||||
FILETIME lastWriteTime;
|
||||
DWORD fileAttributes;
|
||||
};
|
||||
|
||||
struct ResourceFlags
|
||||
{
|
||||
// TODO: figure out which is physical and which is virtual
|
||||
uint32_t flag1;
|
||||
uint32_t flag2;
|
||||
};
|
||||
|
||||
// since Payne, RAGE devices are thread-safe (might not apply to V?)
|
||||
// in V, RAGE devices use UTF-8
|
||||
class fiDevice
|
||||
{
|
||||
public:
|
||||
static inline fiDevice* GetDevice(const char* path, bool allowRoot)
|
||||
{
|
||||
return big::g_pointers->m_fidevice_get_device(path, allowRoot);
|
||||
}
|
||||
|
||||
static bool MountGlobal(const char* mountPoint, fiDevice* device, bool allowRoot);
|
||||
|
||||
static void Unmount(const char* rootPath);
|
||||
|
||||
static void Unmount(fiDevice const& device);
|
||||
|
||||
public:
|
||||
virtual ~fiDevice() = 0;
|
||||
|
||||
virtual uint64_t Open(const char* fileName, bool readOnly) = 0;
|
||||
|
||||
virtual uint64_t OpenBulk(const char* fileName, uint64_t* ptr) = 0;
|
||||
|
||||
virtual uint64_t OpenBulkWrap(const char* fileName, uint64_t* ptr, void*) = 0;
|
||||
|
||||
virtual uint64_t CreateLocal(const char* fileName) = 0;
|
||||
|
||||
virtual uint64_t Create(const char* fileName) = 0;
|
||||
|
||||
virtual uint32_t Read(uint64_t handle, void* buffer, uint32_t toRead) = 0;
|
||||
|
||||
virtual uint32_t ReadBulk(uint64_t handle, uint64_t ptr, void* buffer, uint32_t toRead) = 0;
|
||||
|
||||
virtual uint32_t WriteBulk(uint64_t, int, int, int, int) = 0;
|
||||
|
||||
virtual uint32_t Write(uint64_t, void*, int) = 0;
|
||||
|
||||
virtual uint32_t Seek(uint64_t handle, int32_t distance, uint32_t method) = 0;
|
||||
|
||||
virtual uint64_t SeekLong(uint64_t handle, int64_t distance, uint32_t method) = 0;
|
||||
|
||||
virtual int32_t Close(uint64_t handle) = 0;
|
||||
|
||||
virtual int32_t CloseBulk(uint64_t handle) = 0;
|
||||
|
||||
virtual int GetFileLength(uint64_t handle) = 0;
|
||||
|
||||
virtual uint64_t GetFileLengthUInt64(uint64_t handle) = 0;
|
||||
|
||||
// dummy!
|
||||
virtual int m_40(int) = 0;
|
||||
|
||||
virtual bool RemoveFile(const char* file) = 0;
|
||||
virtual int RenameFile(const char* from, const char* to) = 0;
|
||||
virtual int CreateDirectory(const char* dir) = 0;
|
||||
|
||||
virtual int RemoveDirectory(const char* dir) = 0;
|
||||
|
||||
virtual void m_xx() = 0;
|
||||
|
||||
virtual uint64_t GetFileLengthLong(const char* fileName) = 0;
|
||||
|
||||
virtual uint64_t GetFileTime(const char* file) = 0;
|
||||
virtual bool SetFileTime(const char* file, FILETIME fileTime) = 0;
|
||||
|
||||
virtual uint64_t FindFirst(const char* path, fiFindData* findData) = 0;
|
||||
virtual bool FindNext(uint64_t handle, fiFindData* findData) = 0;
|
||||
virtual int FindClose(uint64_t handle) = 0;
|
||||
|
||||
virtual rage::fiDevice* GetUnkDevice() = 0;
|
||||
|
||||
virtual void* m_xy(void*, int, void*) = 0;
|
||||
|
||||
virtual bool Truncate(uint64_t handle) = 0;
|
||||
|
||||
virtual uint32_t GetFileAttributes(const char* path) = 0;
|
||||
|
||||
virtual bool m_xz() = 0;
|
||||
|
||||
virtual bool SetFileAttributes(const char* file, uint32_t FileAttributes) = 0;
|
||||
|
||||
virtual int m_yx() = 0;
|
||||
|
||||
// read even if read() returns less than length
|
||||
virtual bool ReadFull(uint64_t handle, void* buffer, uint32_t length) = 0;
|
||||
|
||||
virtual bool WriteFull(uint64_t handle, void* buffer, uint32_t length) = 0;
|
||||
|
||||
virtual int32_t GetResourceVersion(const char* fileName, ResourceFlags* flags) = 0;
|
||||
|
||||
virtual int32_t m_yy() = 0;
|
||||
|
||||
virtual int32_t m_yz(void*) = 0;
|
||||
|
||||
virtual int32_t m_zx(void*) = 0; // return 0x40000000
|
||||
|
||||
virtual bool IsCollection() = 0;
|
||||
|
||||
virtual bool m_addedIn1290() = 0;
|
||||
|
||||
virtual fiDevice* GetCollection() = 0; // return this
|
||||
|
||||
virtual bool m_ax() = 0;
|
||||
|
||||
virtual int32_t GetCollectionId() = 0;
|
||||
|
||||
virtual const char* GetName() = 0;
|
||||
};
|
||||
|
||||
class fiDeviceImplemented : public fiDevice
|
||||
{
|
||||
protected:
|
||||
fiDeviceImplemented();
|
||||
|
||||
public:
|
||||
virtual ~fiDeviceImplemented();
|
||||
|
||||
virtual uint64_t Open(const char* fileName, bool readOnly);
|
||||
|
||||
virtual uint64_t OpenBulk(const char* fileName, uint64_t* ptr);
|
||||
|
||||
virtual uint64_t OpenBulkWrap(const char* fileName, uint64_t* ptr, void* a3);
|
||||
|
||||
virtual uint64_t CreateLocal(const char* fileName);
|
||||
|
||||
virtual uint64_t Create(const char* fileName);
|
||||
|
||||
virtual uint32_t Read(uint64_t handle, void* buffer, uint32_t toRead);
|
||||
|
||||
virtual uint32_t ReadBulk(uint64_t handle, uint64_t ptr, void* buffer, uint32_t toRead);
|
||||
|
||||
virtual uint32_t WriteBulk(uint64_t, int, int, int, int);
|
||||
|
||||
virtual uint32_t Write(uint64_t, void*, int);
|
||||
|
||||
virtual uint32_t Seek(uint64_t handle, int32_t distance, uint32_t method);
|
||||
|
||||
virtual uint64_t SeekLong(uint64_t handle, int64_t distance, uint32_t method);
|
||||
|
||||
virtual int32_t Close(uint64_t handle);
|
||||
|
||||
virtual int32_t CloseBulk(uint64_t handle);
|
||||
|
||||
virtual int GetFileLength(uint64_t handle);
|
||||
|
||||
virtual uint64_t GetFileLengthUInt64(uint64_t handle);
|
||||
|
||||
// dummy!
|
||||
virtual int m_40(int);
|
||||
|
||||
virtual bool RemoveFile(const char* file);
|
||||
virtual int RenameFile(const char* from, const char* to);
|
||||
virtual int CreateDirectory(const char* dir);
|
||||
|
||||
virtual int RemoveDirectory(const char* dir);
|
||||
|
||||
virtual void m_xx();
|
||||
|
||||
virtual uint64_t GetFileLengthLong(const char* fileName);
|
||||
|
||||
virtual uint64_t GetFileTime(const char* file);
|
||||
virtual bool SetFileTime(const char* file, FILETIME fileTime);
|
||||
|
||||
virtual uint64_t FindFirst(const char* path, fiFindData* findData);
|
||||
virtual bool FindNext(uint64_t handle, fiFindData* findData);
|
||||
virtual int FindClose(uint64_t handle);
|
||||
|
||||
virtual rage::fiDevice* GetUnkDevice();
|
||||
|
||||
virtual void* m_xy(void* a1, int a2, void* a3);
|
||||
|
||||
virtual bool Truncate(uint64_t handle);
|
||||
|
||||
virtual uint32_t GetFileAttributes(const char* path);
|
||||
|
||||
virtual bool m_xz();
|
||||
|
||||
virtual bool SetFileAttributes(const char* file, uint32_t FileAttributes);
|
||||
|
||||
virtual int m_yx();
|
||||
|
||||
// read even if read() returns less than length
|
||||
virtual bool ReadFull(uint64_t handle, void* buffer, uint32_t length);
|
||||
|
||||
virtual bool WriteFull(uint64_t handle, void* buffer, uint32_t length);
|
||||
|
||||
virtual int32_t GetResourceVersion(const char* fileName, ResourceFlags* version);
|
||||
|
||||
virtual int32_t m_yy();
|
||||
|
||||
virtual int32_t m_yz(void*);
|
||||
|
||||
virtual int32_t m_zx(void*); // return 0x40000000
|
||||
|
||||
virtual bool IsCollection();
|
||||
|
||||
virtual bool m_addedIn1290();
|
||||
|
||||
virtual fiDevice* GetCollection(); // return this
|
||||
|
||||
virtual bool m_ax();
|
||||
|
||||
virtual int32_t GetCollectionId();
|
||||
|
||||
virtual const char* GetName();
|
||||
};
|
||||
|
||||
class fiDeviceRelative : public fiDeviceImplemented
|
||||
{
|
||||
private:
|
||||
char m_pad[272];
|
||||
public:
|
||||
fiDeviceRelative();
|
||||
|
||||
// any RAGE path can be used; including root-relative paths
|
||||
void SetPath(const char* relativeTo, rage::fiDevice* baseDevice, bool allowRoot);
|
||||
|
||||
// compatibility wrapper for NY code
|
||||
inline void SetPath(const char* relativeTo, bool allowRoot)
|
||||
{
|
||||
SetPath(relativeTo, nullptr, allowRoot);
|
||||
}
|
||||
|
||||
// mounts the device in the device stack
|
||||
void Mount(const char* mountPoint);
|
||||
};
|
||||
|
||||
class fiEncryptingDevice : public fiDeviceImplemented
|
||||
{
|
||||
private:
|
||||
void* m_keyState;
|
||||
void* m_0010;
|
||||
char m_buffer[4096];
|
||||
bool m_1018;
|
||||
alignas(int) char m_pad[64]; // unsure
|
||||
|
||||
private:
|
||||
void* AllocKeyState(const uint8_t* key);
|
||||
|
||||
public:
|
||||
fiEncryptingDevice(const std::array<uint8_t, 32>& key);
|
||||
|
||||
void FreeKeyState();
|
||||
};
|
||||
|
||||
class fiPackfile : public fiDeviceImplemented
|
||||
{
|
||||
private:
|
||||
char m_pad[368 + (0x650 - 0x590)];
|
||||
public:
|
||||
fiPackfile();
|
||||
|
||||
// any RAGE path can be used; including root-relative paths
|
||||
bool OpenPackfile(const char* archive, bool bTrue, int type, intptr_t veryFalse);
|
||||
|
||||
// mounts the device in the device stack
|
||||
bool Mount(const char* mountPoint);
|
||||
|
||||
// closes the package file
|
||||
void ClosePackfile();
|
||||
};
|
||||
}
|
@ -32,7 +32,7 @@ namespace rage
|
||||
class netEventMgr;
|
||||
|
||||
class netSyncTree;
|
||||
|
||||
|
||||
class netObject;
|
||||
class netObjectMgrBase;
|
||||
|
||||
@ -43,6 +43,9 @@ namespace rage
|
||||
class fwRefAwareBase;
|
||||
class fwExtensibleBase;
|
||||
class fwArchetype;
|
||||
|
||||
class fiDevice;
|
||||
class fiPackfile;
|
||||
}
|
||||
|
||||
class GtaThread;
|
||||
|
21
BigBaseV2/src/gta/gxt2.hpp
Normal file
21
BigBaseV2/src/gta/gxt2.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
struct GXT2_metadata
|
||||
{
|
||||
static constexpr auto header = "2TXG";
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct GXT2_key
|
||||
{
|
||||
rage::joaat_t key_hash = -1;
|
||||
uint32_t file_offset_to_text = -1;
|
||||
};
|
||||
static_assert(sizeof(GXT2_key) == 8);
|
||||
#pragma pack(pop)
|
||||
|
||||
struct GXT2_entry
|
||||
{
|
||||
rage::joaat_t hash = -1;
|
||||
std::string text;
|
||||
};
|
@ -344,6 +344,57 @@ namespace big
|
||||
m_reset_network_complaints = ptr.add(1).rip().as<functions::reset_network_complaints>();
|
||||
});
|
||||
|
||||
// fiDevice Get Device
|
||||
main_batch.add("FDGD", "41 B8 07 00 00 00 48 8B F1 E8", [this](memory::handle ptr)
|
||||
{
|
||||
m_fidevice_get_device = ptr.sub(0x1F).as<functions::fidevice_get_device>();
|
||||
});
|
||||
|
||||
// fiDevices
|
||||
main_batch.add("FDS", "74 1B 48 8D 0D ? ? ? ? 41 8B D6", [this](memory::handle ptr)
|
||||
{
|
||||
m_fidevices = ptr.add(5).rip().as<uintptr_t>();
|
||||
m_fidevices_len = ptr.add(5).rip().add(8).as<uint16_t*>();
|
||||
});
|
||||
|
||||
// fiPackfile ctor
|
||||
main_batch.add("FPFC", "44 89 41 28 4C 89 41 38 4C 89 41 50 48 8D", [this](memory::handle ptr)
|
||||
{
|
||||
m_fipackfile_ctor = ptr.sub(0x1E).as<functions::fipackfile_ctor>();
|
||||
m_fipackfile_instances = ptr.add(26).rip().as<rage::fiPackfile**>();
|
||||
});
|
||||
|
||||
// fiPackfile open archive
|
||||
main_batch.add("FPFOA", "48 8D 68 98 48 81 EC 40 01 00 00 41 8B F9", [this](memory::handle ptr)
|
||||
{
|
||||
m_fipackfile_open_archive = ptr.sub(0x18).as<functions::fipackfile_open_archive>();
|
||||
});
|
||||
|
||||
// fiPackfile mount
|
||||
main_batch.add("FPFM", "84 C0 74 1D 48 85 DB 74 0F 48", [this](memory::handle ptr)
|
||||
{
|
||||
m_fipackfile_mount = ptr.sub(0x1E).as<functions::fipackfile_mount>();
|
||||
});
|
||||
|
||||
// fiPackfile unmount
|
||||
main_batch.add("FPFUM", "E8 ? ? ? ? 84 C0 74 37 80 3D", [this](memory::handle ptr)
|
||||
{
|
||||
m_fipackfile_unmount = ptr.add(1).rip().as<functions::fipackfile_unmount>();
|
||||
});
|
||||
|
||||
// fidevice unmount
|
||||
main_batch.add("FPFUM", "E8 ? ? ? ? 84 C0 74 37 80 3D", [this](memory::handle ptr)
|
||||
{
|
||||
m_fipackfile_unmount = ptr.add(1).rip().as<functions::fipackfile_unmount>();
|
||||
});
|
||||
|
||||
// game version + online version
|
||||
main_batch.add("GVOV", "8B C3 33 D2 C6 44 24 20", [this](memory::handle ptr)
|
||||
{
|
||||
m_game_version = ptr.add(0x24).rip().as<const char*>();
|
||||
m_online_version = ptr.add(0x24).rip().add(0x20).as<const char*>();
|
||||
});
|
||||
|
||||
auto mem_region = memory::module(nullptr);
|
||||
main_batch.run(mem_region);
|
||||
|
||||
|
@ -106,6 +106,18 @@ namespace big
|
||||
Network** m_network;
|
||||
|
||||
functions::reset_network_complaints m_reset_network_complaints{};
|
||||
|
||||
functions::fidevice_get_device m_fidevice_get_device{};
|
||||
uintptr_t m_fidevices{};
|
||||
uint16_t* m_fidevices_len{};
|
||||
functions::fipackfile_ctor m_fipackfile_ctor{};
|
||||
rage::fiPackfile** m_fipackfile_instances{};
|
||||
functions::fipackfile_open_archive m_fipackfile_open_archive{};
|
||||
functions::fipackfile_mount m_fipackfile_mount{};
|
||||
functions::fipackfile_unmount m_fipackfile_unmount{};
|
||||
|
||||
const char* m_game_version;
|
||||
const char* m_online_version;
|
||||
};
|
||||
|
||||
inline pointers* g_pointers{};
|
||||
|
84
BigBaseV2/src/services/gta_data/cache_file.cpp
Normal file
84
BigBaseV2/src/services/gta_data/cache_file.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "cache_file.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
cache_file::cache_file(file cache_file, std::uint32_t cache_version) :
|
||||
m_cache_file(cache_file),
|
||||
m_data(nullptr),
|
||||
m_cache_version(cache_version),
|
||||
m_cache_header()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void cache_file::free()
|
||||
{
|
||||
m_data.reset();
|
||||
}
|
||||
|
||||
bool cache_file::load()
|
||||
{
|
||||
if (!m_cache_file.exists())
|
||||
return false;
|
||||
if (m_data)
|
||||
return true;
|
||||
|
||||
auto file = std::ifstream(m_cache_file.get_path(), std::ios::binary);
|
||||
|
||||
file.read(reinterpret_cast<char*>(&m_cache_header), sizeof(m_cache_header));
|
||||
|
||||
m_data = std::make_unique<std::uint8_t[]>(m_cache_header.m_data_size);
|
||||
file.read(reinterpret_cast<char*>(m_data.get()), m_cache_header.m_data_size);
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cache_file::write() const
|
||||
{
|
||||
if (!m_data)
|
||||
return false;
|
||||
|
||||
auto file = std::ofstream(m_cache_file.get_path(), std::ios::binary);
|
||||
|
||||
file.write(reinterpret_cast<const char*>(&m_cache_header), sizeof(m_cache_header));
|
||||
file.write(reinterpret_cast<const char*>(m_data.get()), m_cache_header.m_data_size);
|
||||
file.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::uint8_t* cache_file::data() const
|
||||
{
|
||||
return m_data.get();
|
||||
}
|
||||
|
||||
std::uint64_t cache_file::data_size() const
|
||||
{
|
||||
return m_cache_header.m_data_size;
|
||||
}
|
||||
|
||||
bool cache_file::up_to_date(std::uint32_t game_version, float online_version) const
|
||||
{
|
||||
if (!m_data)
|
||||
return false;
|
||||
|
||||
return
|
||||
m_cache_version == m_cache_header.m_cache_version &&
|
||||
game_version == m_cache_header.m_game_version &&
|
||||
online_version == m_cache_header.m_online_version;
|
||||
}
|
||||
|
||||
void cache_file::set_data(cache_data&& data, std::uint64_t data_size)
|
||||
{
|
||||
m_data.swap(data);
|
||||
m_cache_header.m_data_size = data_size;
|
||||
}
|
||||
|
||||
void cache_file::set_header_version(std::uint32_t game_version, float online_version)
|
||||
{
|
||||
m_cache_header.m_cache_version = m_cache_version;
|
||||
m_cache_header.m_game_version = game_version;
|
||||
m_cache_header.m_online_version = online_version;
|
||||
}
|
||||
}
|
71
BigBaseV2/src/services/gta_data/cache_file.hpp
Normal file
71
BigBaseV2/src/services/gta_data/cache_file.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class cache_header final
|
||||
{
|
||||
public:
|
||||
std::uint32_t m_cache_version;
|
||||
std::uint32_t m_game_version;
|
||||
float m_online_version;
|
||||
std::uint64_t m_data_size;
|
||||
};
|
||||
|
||||
using cache_data = std::unique_ptr<std::uint8_t[]>;
|
||||
class cache_file final
|
||||
{
|
||||
public:
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="cache_file">FileMgr file object</param>
|
||||
/// <param name="cache_version">Internal version, use this to invalidate the cache when changing the structure of the data</param>
|
||||
cache_file(file cache_file, std::uint32_t cache_version);
|
||||
|
||||
/// <summary>
|
||||
/// Frees any memory used to hold the cached data.
|
||||
/// </summary>
|
||||
void free();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to load the cache from disk
|
||||
/// </summary>
|
||||
/// <returns>True after successfully loading the data, false if the file didn't exist.</returns>
|
||||
bool load();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the cache to disk
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
bool write() const;
|
||||
|
||||
std::uint8_t* data() const;
|
||||
std::uint64_t data_size() const;
|
||||
|
||||
/// <summary>
|
||||
/// Check if the cache file is up to date with the expected versions
|
||||
/// </summary>
|
||||
/// <param name="game_version">Current Game version</param>
|
||||
/// <param name="online_version">Current Online version</param>
|
||||
/// <returns>True if cache is up to date, false otherwise.</returns>
|
||||
bool up_to_date(std::uint32_t game_version, float online_version) const;
|
||||
|
||||
|
||||
void set_data(cache_data&& data, std::uint64_t data_size);
|
||||
/// <summary>
|
||||
/// Sets the version information of the cache header.
|
||||
/// </summary>
|
||||
/// <param name="game_version">Game Build</param>
|
||||
/// <param name="online_version">Online Version</param>
|
||||
void set_header_version(std::uint32_t game_version, float online_version);
|
||||
|
||||
private:
|
||||
file m_cache_file;
|
||||
|
||||
std::uint32_t m_cache_version;
|
||||
|
||||
cache_header m_cache_header;
|
||||
cache_data m_data;
|
||||
};
|
||||
}
|
@ -1,48 +1,35 @@
|
||||
#include "api/remote.hpp"
|
||||
#include "file_manager.hpp"
|
||||
#include "thread_pool.hpp"
|
||||
#include "gta_data_service.hpp"
|
||||
|
||||
#define EXIST_IN_ARRAY(arr, val) (std::find(std::begin(arr), std::end(arr), val) != std::end(arr))
|
||||
#include "file_manager.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "pugixml.hpp"
|
||||
#include "script.hpp"
|
||||
#include "thread_pool.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include "yim_fipackfile.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
gta_data_service::gta_data_service()
|
||||
bool add_if_not_exists(string_vec& vec, std::string str)
|
||||
{
|
||||
g_thread_pool->push([this] {
|
||||
while (!g_running)
|
||||
std::this_thread::sleep_for(1s);
|
||||
if (std::find(vec.begin(), vec.end(), str) != vec.end())
|
||||
return true;
|
||||
|
||||
const std::string url_prefix = "http://github-proxy.damon.sh/DurtyFree/gta-v-data-dumps/master/";
|
||||
vec.emplace_back(std::move(str));
|
||||
return false;
|
||||
}
|
||||
|
||||
this->load_from_file(
|
||||
"./lib/vehicles.json",
|
||||
"./lib/vehicles_etag.txt",
|
||||
url_prefix + "vehicles.json",
|
||||
>a_data_service::load_vehicles,
|
||||
"Vehicle"
|
||||
);
|
||||
|
||||
std::this_thread::sleep_for(1s);
|
||||
|
||||
this->load_from_file(
|
||||
"./lib/peds.json",
|
||||
"./lib/peds_etag.txt",
|
||||
url_prefix + "peds.json",
|
||||
>a_data_service::load_peds,
|
||||
"Ped"
|
||||
);
|
||||
|
||||
std::this_thread::sleep_for(1s);
|
||||
|
||||
this->load_from_file(
|
||||
"./lib/weapons.json",
|
||||
"./lib/weapons_etag.txt",
|
||||
url_prefix + "weapons.json",
|
||||
>a_data_service::load_weapons,
|
||||
"Weapon"
|
||||
);
|
||||
});
|
||||
gta_data_service::gta_data_service() :
|
||||
m_peds_cache(g_file_manager->get_project_file("./cache/peds.bin"), 1),
|
||||
m_vehicles_cache(g_file_manager->get_project_file("./cache/vehicles.bin"), 1),
|
||||
m_weapons_cache(g_file_manager->get_project_file("./cache/weapons.bin"), 1),
|
||||
m_update_state(eGtaDataUpdateState::IDLE)
|
||||
{
|
||||
if (!is_cache_up_to_date())
|
||||
m_update_state = eGtaDataUpdateState::NEEDS_UPDATE;
|
||||
else
|
||||
load_data();
|
||||
|
||||
g_gta_data_service = this;
|
||||
}
|
||||
@ -52,343 +39,391 @@ namespace big
|
||||
g_gta_data_service = nullptr;
|
||||
}
|
||||
|
||||
const vehicle_item& gta_data_service::find_vehicle_by_hash(Hash hash)
|
||||
bool gta_data_service::cache_needs_update() const
|
||||
{
|
||||
int idx = -1;
|
||||
return m_update_state == eGtaDataUpdateState::NEEDS_UPDATE;
|
||||
}
|
||||
|
||||
if (m_vehicle_hash_idx_map.count(hash))
|
||||
eGtaDataUpdateState gta_data_service::state() const
|
||||
{
|
||||
return m_update_state;
|
||||
}
|
||||
|
||||
void gta_data_service::update_in_online()
|
||||
{
|
||||
m_update_state = eGtaDataUpdateState::WAITING_FOR_ONLINE;
|
||||
|
||||
g_fiber_pool->queue_job([this]
|
||||
{
|
||||
idx = m_vehicle_hash_idx_map[hash];
|
||||
}
|
||||
session::join_type(eSessionType::SOLO);
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
return empty_vehicle_item;
|
||||
}
|
||||
|
||||
return m_vehicle_item_arr[idx];
|
||||
}
|
||||
|
||||
const std::vector<std::string>& gta_data_service::get_vehicle_class_arr()
|
||||
{
|
||||
return m_vehicle_class_arr;
|
||||
}
|
||||
|
||||
const std::vector<vehicle_item>& gta_data_service::get_vehicle_arr()
|
||||
{
|
||||
return m_vehicle_item_arr;
|
||||
}
|
||||
|
||||
|
||||
const ped_item& gta_data_service::find_ped_by_hash(Hash hash)
|
||||
{
|
||||
int idx = -1;
|
||||
|
||||
if (m_ped_hash_idx_map.count(hash))
|
||||
{
|
||||
idx = m_ped_hash_idx_map[hash];
|
||||
}
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
return empty_ped_item;
|
||||
}
|
||||
|
||||
return m_ped_item_arr[idx];
|
||||
}
|
||||
|
||||
const std::vector<std::string>& gta_data_service::get_ped_type_arr()
|
||||
{
|
||||
return m_ped_type_arr;
|
||||
}
|
||||
|
||||
const std::vector<ped_item>& gta_data_service::get_ped_arr()
|
||||
{
|
||||
return m_ped_item_arr;
|
||||
}
|
||||
|
||||
|
||||
const weapon_item& gta_data_service::find_weapon_by_hash(Hash hash)
|
||||
{
|
||||
int idx = -1;
|
||||
|
||||
if (m_weapon_hash_idx_map.count(hash))
|
||||
{
|
||||
idx = m_weapon_hash_idx_map[hash];
|
||||
}
|
||||
|
||||
if (idx == -1)
|
||||
{
|
||||
return empty_weapon_item;
|
||||
}
|
||||
|
||||
return m_weapon_item_arr[idx];
|
||||
}
|
||||
|
||||
const std::vector<std::string>& gta_data_service::get_weapon_type_arr()
|
||||
{
|
||||
return m_weapon_type_arr;
|
||||
}
|
||||
|
||||
const std::vector<weapon_item>& gta_data_service::get_weapon_arr()
|
||||
{
|
||||
return m_weapon_item_arr;
|
||||
}
|
||||
|
||||
|
||||
void gta_data_service::load_from_file(
|
||||
std::string file_path, std::string etag_path, std::string url,
|
||||
bool(gta_data_service::* load_func)(std::filesystem::path), std::string data_name
|
||||
) {
|
||||
file file_to_load(g_file_manager->get_project_file(file_path));
|
||||
file file_etag(g_file_manager->get_project_file(etag_path));
|
||||
auto file_to_load_path = file_to_load.get_path();
|
||||
auto file_etag_path = file_etag.get_path();
|
||||
|
||||
bool up_to_date = false;
|
||||
|
||||
for (int retry = 0; retry < 3 && g_running; retry++)
|
||||
{
|
||||
LOG(INFO) << "Checking update (attempt: " << (retry + 1) << "/3): " << data_name;
|
||||
|
||||
try
|
||||
while (!*g_pointers->m_is_session_started)
|
||||
{
|
||||
bool ret = remote::update_binary(
|
||||
url,
|
||||
file_to_load_path,
|
||||
file_etag_path
|
||||
);
|
||||
script::get_current()->yield(100ms);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
rebuild_cache();
|
||||
});
|
||||
}
|
||||
|
||||
void gta_data_service::update_now()
|
||||
{
|
||||
g_fiber_pool->queue_job([this]
|
||||
{
|
||||
rebuild_cache();
|
||||
});
|
||||
}
|
||||
|
||||
// innefficient getters, don't care to fix right now
|
||||
const ped_item& gta_data_service::ped_by_hash(std::uint32_t hash)
|
||||
{
|
||||
for (const auto& [name, ped] : m_peds)
|
||||
if (rage::joaat(name) == hash)
|
||||
return ped;
|
||||
return gta_data_service::empty_ped;
|
||||
}
|
||||
|
||||
const vehicle_item& gta_data_service::vehicle_by_hash(std::uint32_t hash)
|
||||
{
|
||||
for (const auto& [name, veh] : m_vehicles)
|
||||
if (rage::joaat(name) == hash)
|
||||
return veh;
|
||||
return gta_data_service::empty_vehicle;
|
||||
}
|
||||
|
||||
const weapon_item& gta_data_service::weapon_by_hash(std::uint32_t hash)
|
||||
{
|
||||
for (const auto& [name, weapon] : m_weapons)
|
||||
if (rage::joaat(name) == hash)
|
||||
return weapon;
|
||||
return gta_data_service::empty_weapon;
|
||||
}
|
||||
|
||||
string_vec& gta_data_service::ped_types()
|
||||
{
|
||||
return m_ped_types;
|
||||
}
|
||||
|
||||
string_vec& gta_data_service::vehicle_classes()
|
||||
{
|
||||
return m_vehicle_classes;
|
||||
}
|
||||
|
||||
string_vec& gta_data_service::weapon_types()
|
||||
{
|
||||
return m_weapon_types;
|
||||
}
|
||||
|
||||
bool gta_data_service::is_cache_up_to_date()
|
||||
{
|
||||
m_peds_cache.load();
|
||||
m_vehicles_cache.load();
|
||||
m_weapons_cache.load();
|
||||
|
||||
const auto game_version = std::strtoul(g_pointers->m_game_version, nullptr, 10);
|
||||
const auto online_version = std::strtof(g_pointers->m_online_version, nullptr);
|
||||
|
||||
return
|
||||
m_peds_cache.up_to_date(game_version, online_version) &&
|
||||
m_vehicles_cache.up_to_date(game_version, online_version) &&
|
||||
m_weapons_cache.up_to_date(game_version, online_version);
|
||||
}
|
||||
|
||||
void gta_data_service::load_data()
|
||||
{
|
||||
LOG(G3LOG_DEBUG) << "Loading data from cache.";
|
||||
|
||||
load_peds();
|
||||
load_vehicles();
|
||||
load_weapons();
|
||||
|
||||
LOG(G3LOG_DEBUG) << "Loaded all data from cache.";
|
||||
}
|
||||
|
||||
void gta_data_service::load_peds()
|
||||
{
|
||||
const auto ped_count = m_peds_cache.data_size() / sizeof(ped_item);
|
||||
LOG(INFO) << "Loading " << ped_count << " peds from cache.";
|
||||
|
||||
auto cached_peds = reinterpret_cast<const ped_item*>(m_peds_cache.data());
|
||||
for (size_t i = 0; i < ped_count; i++)
|
||||
{
|
||||
const auto ped = cached_peds[i];
|
||||
|
||||
add_if_not_exists(m_ped_types, ped.m_ped_type);
|
||||
m_peds.insert({ ped.m_name, ped });
|
||||
}
|
||||
|
||||
std::sort(m_ped_types.begin(), m_ped_types.end());
|
||||
m_peds_cache.free();
|
||||
}
|
||||
|
||||
void gta_data_service::load_vehicles()
|
||||
{
|
||||
const auto vehicle_count = m_vehicles_cache.data_size() / sizeof(vehicle_item);
|
||||
LOG(INFO) << "Loading " << vehicle_count << " vehicles from cache.";
|
||||
|
||||
auto cached_vehicles = reinterpret_cast<const vehicle_item*>(m_vehicles_cache.data());
|
||||
for (size_t i = 0; i < vehicle_count; i++)
|
||||
{
|
||||
const auto vehicle = cached_vehicles[i];
|
||||
|
||||
add_if_not_exists(m_vehicle_classes, vehicle.m_vehicle_class);
|
||||
m_vehicles.insert({ vehicle.m_name, vehicle });
|
||||
}
|
||||
|
||||
std::sort(m_vehicle_classes.begin(), m_vehicle_classes.end());
|
||||
m_vehicles_cache.free();
|
||||
}
|
||||
|
||||
void gta_data_service::load_weapons()
|
||||
{
|
||||
const auto weapon_count = m_weapons_cache.data_size() / sizeof(weapon_item);
|
||||
LOG(INFO) << "Loading " << weapon_count << " weapons from cache.";
|
||||
|
||||
auto cached_weapons = reinterpret_cast<const weapon_item*>(m_weapons_cache.data());
|
||||
for (size_t i = 0; i < weapon_count; i++)
|
||||
{
|
||||
const auto weapon = cached_weapons[i];
|
||||
|
||||
add_if_not_exists(m_weapon_types, weapon.m_weapon_type);
|
||||
m_weapons.insert({ weapon.m_name, weapon });
|
||||
}
|
||||
|
||||
std::sort(m_weapon_types.begin(), m_weapon_types.end());
|
||||
m_weapons_cache.free();
|
||||
}
|
||||
|
||||
void gta_data_service::rebuild_cache()
|
||||
{
|
||||
m_update_state = eGtaDataUpdateState::UPDATING;
|
||||
|
||||
using hash_array = std::vector<std::uint32_t>;
|
||||
hash_array mapped_peds;
|
||||
hash_array mapped_vehicles;
|
||||
hash_array mapped_weapons;
|
||||
|
||||
std::vector<ped_item> peds;
|
||||
std::vector<vehicle_item> vehicles;
|
||||
std::vector<weapon_item> weapons;
|
||||
|
||||
constexpr auto exists = [](const hash_array& arr, std::uint32_t val) -> bool
|
||||
{
|
||||
return std::find(arr.begin(), arr.end(), val) != arr.end();
|
||||
};
|
||||
|
||||
LOG(INFO) << "Rebuilding cache started...";
|
||||
yim_fipackfile::for_each_fipackfile([&](yim_fipackfile& rpf_wrapper)
|
||||
{
|
||||
const auto files = rpf_wrapper.get_file_paths();
|
||||
for (const auto& file : files)
|
||||
{
|
||||
if (file.filename() == "setup2.xml")
|
||||
{
|
||||
up_to_date = true;
|
||||
|
||||
LOG(INFO) << "Data updated: " << data_name;
|
||||
|
||||
if ((this->*load_func)(file_to_load_path))
|
||||
std::string dlc_name;
|
||||
rpf_wrapper.read_xml_file(file, [&dlc_name](pugi::xml_document& doc)
|
||||
{
|
||||
LOG(INFO) << "Data loaded: " + data_name;
|
||||
break;
|
||||
}
|
||||
else
|
||||
const auto item = doc.select_node("/SSetupData/nameHash");
|
||||
dlc_name = item.node().text().as_string();
|
||||
});
|
||||
|
||||
if (dlc_name == "mpG9EC")
|
||||
{
|
||||
std::filesystem::remove(file_to_load_path);
|
||||
std::filesystem::remove(file_etag_path);
|
||||
LOG(G3LOG_DEBUG) << "Bad DLC, skipping...";
|
||||
|
||||
return std::size_t(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG(WARNING) << "Data invalid: " + data_name;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(2s);
|
||||
}
|
||||
|
||||
if (!up_to_date)
|
||||
{
|
||||
LOG(WARNING) << "Data not updated: " + data_name;
|
||||
|
||||
try
|
||||
{
|
||||
if (file_to_load.exists())
|
||||
else if (file.filename() == "vehicles.meta")
|
||||
{
|
||||
if ((this->*load_func)(file_to_load_path))
|
||||
rpf_wrapper.read_xml_file(file, [&exists, &vehicles, &mapped_vehicles](pugi::xml_document& doc)
|
||||
{
|
||||
LOG(INFO) << "Cache loaded: " + data_name;
|
||||
}
|
||||
else
|
||||
const auto& items = doc.select_nodes("/CVehicleModelInfo__InitDataList/InitDatas/Item");
|
||||
for (const auto& item_node : items)
|
||||
{
|
||||
const auto item = item_node.node();
|
||||
|
||||
const auto name = item.child("modelName").text().as_string();
|
||||
const auto hash = rage::joaat(name);
|
||||
|
||||
if (exists(mapped_vehicles, hash))
|
||||
continue;
|
||||
mapped_vehicles.emplace_back(hash);
|
||||
|
||||
auto veh = vehicle_item{};
|
||||
std::strncpy(veh.m_name, name, sizeof(veh.m_name));
|
||||
|
||||
const auto manufacturer_display = item.child("vehicleMakeName").text().as_string();
|
||||
std::strncpy(
|
||||
veh.m_display_manufacturer,
|
||||
HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(manufacturer_display),
|
||||
sizeof(veh.m_display_manufacturer));
|
||||
|
||||
const auto game_name = item.child("gameName").text().as_string();
|
||||
std::strncpy(
|
||||
veh.m_display_name,
|
||||
HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(game_name),
|
||||
sizeof(veh.m_display_name));
|
||||
|
||||
const auto vehicle_class = item.child("vehicleClass").text().as_string();
|
||||
constexpr auto enum_prefix_len = 3;
|
||||
if (std::strlen(vehicle_class) > enum_prefix_len)
|
||||
std::strncpy(veh.m_vehicle_class, vehicle_class + enum_prefix_len, sizeof(veh.m_vehicle_class));
|
||||
|
||||
veh.m_hash = hash;
|
||||
|
||||
vehicles.emplace_back(std::move(veh));
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (const auto file_str = file.string(); file_str.find("weapon") != std::string::npos && file.extension() == ".meta")
|
||||
{
|
||||
rpf_wrapper.read_xml_file(file, [&exists, &weapons, &mapped_weapons](pugi::xml_document& doc)
|
||||
{
|
||||
std::filesystem::remove(file_to_load_path);
|
||||
std::filesystem::remove(file_etag_path);
|
||||
throw std::exception("");
|
||||
}
|
||||
const auto& items = doc.select_nodes("/CWeaponInfoBlob/Infos/Item/Infos/Item[@type='CWeaponInfo']");
|
||||
for (const auto& item_node : items)
|
||||
{
|
||||
const auto item = item_node.node();
|
||||
const auto name = item.child("Name").text().as_string();
|
||||
const auto hash = rage::joaat(name);
|
||||
|
||||
if (exists(mapped_weapons, hash))
|
||||
continue;
|
||||
mapped_weapons.emplace_back(hash);
|
||||
|
||||
const auto human_name_hash = item.child("HumanNameHash").text().as_string();
|
||||
if (std::strcmp(human_name_hash, "WT_INVALID") == 0)
|
||||
continue;
|
||||
|
||||
auto weapon = weapon_item{};
|
||||
|
||||
std::strncpy(weapon.m_name, name, sizeof(weapon.m_name));
|
||||
|
||||
const auto display_name = HUD::GET_FILENAME_FOR_AUDIO_CONVERSATION(human_name_hash);
|
||||
std::strncpy(weapon.m_display_name, display_name, sizeof(weapon.m_name));
|
||||
|
||||
auto weapon_flags = std::string(
|
||||
item.child("WeaponFlags").text().as_string()
|
||||
);
|
||||
|
||||
bool is_gun = false;
|
||||
bool is_rechargable = false;
|
||||
|
||||
std::size_t pos;
|
||||
while ((pos = weapon_flags.find(' ')) != std::string::npos) {
|
||||
const auto flag = weapon_flags.substr(0, pos);
|
||||
if (flag == "Thrown")
|
||||
{
|
||||
weapon.m_throwable = true;
|
||||
}
|
||||
else if (flag == "Gun")
|
||||
{
|
||||
is_gun = true;
|
||||
}
|
||||
else if (flag == "DisplayRechargeTimeHUD")
|
||||
{
|
||||
is_rechargable = true;
|
||||
}
|
||||
|
||||
weapon_flags.erase(0, pos + 1);
|
||||
}
|
||||
|
||||
const auto category = item.child("Group").text().as_string();
|
||||
if (std::strlen(category) > 6)
|
||||
{
|
||||
std::strncpy(weapon.m_weapon_type, category + 6, sizeof(weapon.m_weapon_type));
|
||||
}
|
||||
|
||||
if (is_gun || !std::strcmp(weapon.m_weapon_type, "MELEE") || !std::strcmp(weapon.m_weapon_type, "UNARMED"))
|
||||
{
|
||||
const std::string reward_prefix = "REWARD_";
|
||||
weapon.m_reward_hash = rage::joaat(reward_prefix + name);
|
||||
|
||||
if (is_gun && !is_rechargable)
|
||||
{
|
||||
std::string weapon_id = name + 7;
|
||||
weapon.m_reward_ammo_hash = rage::joaat(reward_prefix + "AMMO_" + weapon_id);
|
||||
}
|
||||
}
|
||||
|
||||
weapon.m_hash = hash;
|
||||
|
||||
weapons.emplace_back(std::move(weapon));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG(WARNING) << "Cache invalid: " + data_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool gta_data_service::load_vehicles(std::filesystem::path path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
nlohmann::json all_vehicles;
|
||||
|
||||
try
|
||||
{
|
||||
file >> all_vehicles;
|
||||
|
||||
if (!all_vehicles.is_array())
|
||||
{
|
||||
throw std::exception("Invalid json format.");
|
||||
}
|
||||
|
||||
m_vehicle_class_arr.clear();
|
||||
m_vehicle_hash_idx_map.clear();
|
||||
m_vehicle_item_arr.clear();
|
||||
|
||||
for (auto& item_json : all_vehicles)
|
||||
{
|
||||
if (
|
||||
item_json["Hash"].is_null() ||
|
||||
item_json["Name"].is_null() ||
|
||||
item_json["MonetaryValue"] == 0 ||
|
||||
!item_json["Bones"].is_array() ||
|
||||
item_json["Bones"][0] == "stub"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto item = vehicle_item(item_json);
|
||||
|
||||
m_vehicle_hash_idx_map[item_json["Hash"]] = (int)m_vehicle_item_arr.size();
|
||||
|
||||
m_vehicle_item_arr.push_back(item);
|
||||
|
||||
if (std::find(m_vehicle_class_arr.begin(), m_vehicle_class_arr.end(), item.clazz) == m_vehicle_class_arr.end())
|
||||
else if (file.filename() == "peds.meta" || file.filename() == "peds.ymt")
|
||||
{
|
||||
m_vehicle_class_arr.push_back(item.clazz);
|
||||
rpf_wrapper.read_xml_file(file, [&exists, &peds, &mapped_peds](pugi::xml_document& doc)
|
||||
{
|
||||
const auto& items = doc.select_nodes("/CPedModelInfo__InitDataList/InitDatas/Item");
|
||||
for (const auto& item_node : items)
|
||||
{
|
||||
const auto& item = item_node.node();
|
||||
const auto name = item.child("Name").text().as_string();
|
||||
const auto hash = rage::joaat(name);
|
||||
|
||||
if (exists(mapped_peds, hash))
|
||||
continue;
|
||||
mapped_peds.emplace_back(hash);
|
||||
|
||||
auto ped = ped_item{};
|
||||
|
||||
std::strncpy(ped.m_name, name, sizeof(ped.m_name));
|
||||
|
||||
const auto ped_type = item.child("Pedtype").text().as_string();
|
||||
std::strncpy(ped.m_ped_type, ped_type, sizeof(ped.m_ped_type));
|
||||
|
||||
ped.m_hash = hash;
|
||||
|
||||
peds.emplace_back(std::move(ped));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::sort(m_vehicle_class_arr.begin(), m_vehicle_class_arr.end());
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
|
||||
return files.size();
|
||||
});
|
||||
|
||||
m_update_state = eGtaDataUpdateState::IDLE;
|
||||
LOG(INFO) << "Cache has been rebuilt.\n\tPeds: " << peds.size() << "\n\tVehicles: " << vehicles.size() << "\n\tWeapons: " << weapons.size();
|
||||
|
||||
LOG(G3LOG_DEBUG) << "Starting cache saving procedure...";
|
||||
g_thread_pool->push([this, peds = std::move(peds), vehicles = std::move(vehicles), weapons = std::move(weapons)]
|
||||
{
|
||||
LOG(WARNING) << "Failed to load vehicles.json:\n" << ex.what();
|
||||
return false;
|
||||
}
|
||||
const auto game_version = std::strtoul(g_pointers->m_game_version, nullptr, 10);
|
||||
const auto online_version = std::strtof(g_pointers->m_online_version, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool gta_data_service::load_peds(std::filesystem::path path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
nlohmann::json all_peds;
|
||||
|
||||
try
|
||||
{
|
||||
file >> all_peds;
|
||||
|
||||
if (!all_peds.is_array())
|
||||
{
|
||||
throw std::exception("Invalid json format.");
|
||||
const auto data_size = sizeof(ped_item) * peds.size();
|
||||
m_peds_cache.set_data(std::make_unique<std::uint8_t[]>(data_size), data_size);
|
||||
std::memcpy(m_peds_cache.data(), peds.data(), data_size);
|
||||
|
||||
m_peds_cache.set_header_version(game_version, online_version);
|
||||
m_peds_cache.write();
|
||||
}
|
||||
|
||||
m_ped_type_arr.clear();
|
||||
m_ped_hash_idx_map.clear();
|
||||
m_ped_item_arr.clear();
|
||||
|
||||
for (auto& item_json : all_peds)
|
||||
{
|
||||
if (
|
||||
item_json["Hash"].is_null() ||
|
||||
item_json["Name"].is_null()
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const auto data_size = sizeof(vehicle_item) * vehicles.size();
|
||||
m_vehicles_cache.set_data(std::make_unique<std::uint8_t[]>(data_size), data_size);
|
||||
std::memcpy(m_vehicles_cache.data(), vehicles.data(), data_size);
|
||||
|
||||
auto item = ped_item(item_json);
|
||||
|
||||
m_ped_hash_idx_map[item_json["Hash"]] = (int)m_ped_item_arr.size();
|
||||
|
||||
m_ped_item_arr.push_back(item);
|
||||
|
||||
if (std::find(m_ped_type_arr.begin(), m_ped_type_arr.end(), item.ped_type) == m_ped_type_arr.end())
|
||||
{
|
||||
m_ped_type_arr.push_back(item.ped_type);
|
||||
}
|
||||
|
||||
std::sort(m_ped_type_arr.begin(), m_ped_type_arr.end());
|
||||
m_vehicles_cache.set_header_version(game_version, online_version);
|
||||
m_vehicles_cache.write();
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
LOG(WARNING) << "Failed to load peds.json:\n" << ex.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool gta_data_service::load_weapons(std::filesystem::path path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
nlohmann::json all_weapons;
|
||||
|
||||
try
|
||||
{
|
||||
file >> all_weapons;
|
||||
|
||||
if (!all_weapons.is_array())
|
||||
{
|
||||
throw std::exception("Invalid json format.");
|
||||
const auto data_size = sizeof(weapon_item) * weapons.size();
|
||||
m_weapons_cache.set_data(std::make_unique<std::uint8_t[]>(data_size), data_size);
|
||||
std::memcpy(m_weapons_cache.data(), weapons.data(), data_size);
|
||||
|
||||
m_weapons_cache.set_header_version(game_version, online_version);
|
||||
m_weapons_cache.write();
|
||||
}
|
||||
|
||||
m_weapon_type_arr.clear();
|
||||
m_weapon_hash_idx_map.clear();
|
||||
m_weapon_item_arr.clear();
|
||||
LOG(INFO) << "Finished writing cache to disk.";
|
||||
|
||||
constexpr Hash hash_blacklist_arr[] = {
|
||||
RAGE_JOAAT("WEAPON_BIRD_CRAP"),
|
||||
RAGE_JOAAT("WEAPON_DIGISCANNER"),
|
||||
RAGE_JOAAT("WEAPON_GARBAGEBAG"),
|
||||
RAGE_JOAAT("WEAPON_GRENADELAUNCHER_SMOKE"),
|
||||
RAGE_JOAAT("WEAPON_HANDCUFFS"),
|
||||
RAGE_JOAAT("WEAPON_METALDETECTOR"),
|
||||
RAGE_JOAAT("GADGET_NIGHTVISION"),
|
||||
RAGE_JOAAT("GADGET_PARACHUTE"),
|
||||
RAGE_JOAAT("WEAPON_TRANQUILIZER"),
|
||||
RAGE_JOAAT("WEAPON_STINGER")
|
||||
};
|
||||
|
||||
for (auto& item_json : all_weapons)
|
||||
{
|
||||
if (
|
||||
item_json["Hash"].is_null() ||
|
||||
item_json["Name"].is_null() ||
|
||||
item_json["IsVehicleWeapon"]
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EXIST_IN_ARRAY(hash_blacklist_arr, item_json["Hash"]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto item = weapon_item(item_json);
|
||||
|
||||
if (item.name == "Invalid" || item.name == "Unarmed" || item.weapon_type == "NULL")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
m_weapon_hash_idx_map[item_json["Hash"]] = (int)m_weapon_item_arr.size();
|
||||
|
||||
m_weapon_item_arr.push_back(item);
|
||||
|
||||
if (std::find(m_weapon_type_arr.begin(), m_weapon_type_arr.end(), item.weapon_type) == m_weapon_type_arr.end())
|
||||
{
|
||||
m_weapon_type_arr.push_back(item.weapon_type);
|
||||
}
|
||||
|
||||
std::sort(m_weapon_type_arr.begin(), m_weapon_type_arr.end());
|
||||
}
|
||||
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
LOG(WARNING) << "Failed to load weapons.json:\n" << ex.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
load_data();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +1,82 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
#include "vehicle_item.hpp"
|
||||
#include "cache_file.hpp"
|
||||
#include "ped_item.hpp"
|
||||
#include "vehicle_item.hpp"
|
||||
#include "weapon_item.hpp"
|
||||
#include "gta/joaat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class gta_data_service
|
||||
enum class eGtaDataUpdateState
|
||||
{
|
||||
std::vector<std::string> m_vehicle_class_arr;
|
||||
std::map<Hash, int> m_vehicle_hash_idx_map;
|
||||
std::vector<vehicle_item> m_vehicle_item_arr;
|
||||
const vehicle_item empty_vehicle_item = vehicle_item();
|
||||
IDLE,
|
||||
NEEDS_UPDATE,
|
||||
WAITING_FOR_ONLINE,
|
||||
UPDATING
|
||||
};
|
||||
|
||||
std::vector<std::string> m_ped_type_arr;
|
||||
std::map<Hash, int> m_ped_hash_idx_map;
|
||||
std::vector<ped_item> m_ped_item_arr;
|
||||
const ped_item empty_ped_item = ped_item();
|
||||
|
||||
std::vector<std::string> m_weapon_type_arr;
|
||||
std::map<Hash, int> m_weapon_hash_idx_map;
|
||||
std::vector<weapon_item> m_weapon_item_arr;
|
||||
const weapon_item empty_weapon_item = weapon_item();
|
||||
using ped_map = std::map<std::string, ped_item>;
|
||||
using vehicle_map = std::map<std::string, vehicle_item>;
|
||||
using weapon_map = std::map<std::string, weapon_item>;
|
||||
using string_vec = std::vector<std::string>;
|
||||
|
||||
class gta_data_service final
|
||||
{
|
||||
public:
|
||||
gta_data_service();
|
||||
~gta_data_service();
|
||||
|
||||
const vehicle_item& find_vehicle_by_hash(Hash hash);
|
||||
const std::vector<std::string>& get_vehicle_class_arr();
|
||||
const std::vector<vehicle_item>& get_vehicle_arr();
|
||||
bool cache_needs_update() const;
|
||||
eGtaDataUpdateState state() const;
|
||||
void update_in_online();
|
||||
void update_now();
|
||||
|
||||
const ped_item& find_ped_by_hash(Hash hash);
|
||||
const std::vector<std::string>& get_ped_type_arr();
|
||||
const std::vector<ped_item>& get_ped_arr();
|
||||
const ped_item& ped_by_hash(std::uint32_t hash);
|
||||
const vehicle_item& vehicle_by_hash(std::uint32_t hash);
|
||||
const weapon_item& weapon_by_hash(std::uint32_t hash);
|
||||
|
||||
const weapon_item& find_weapon_by_hash(Hash hash);
|
||||
const std::vector<std::string>& get_weapon_type_arr();
|
||||
const std::vector<weapon_item>& get_weapon_arr();
|
||||
string_vec& ped_types();
|
||||
string_vec& vehicle_classes();
|
||||
string_vec& weapon_types();
|
||||
|
||||
ped_map& peds()
|
||||
{ return m_peds; }
|
||||
vehicle_map& vehicles()
|
||||
{ return m_vehicles; }
|
||||
weapon_map& weapons()
|
||||
{ return m_weapons; }
|
||||
|
||||
private:
|
||||
void load_from_file(
|
||||
std::string file_path, std::string etag_path, std::string url,
|
||||
bool(gta_data_service::* load_func)(std::filesystem::path), std::string data_name
|
||||
);
|
||||
bool is_cache_up_to_date();
|
||||
|
||||
void load_data();
|
||||
void load_peds();
|
||||
void load_vehicles();
|
||||
void load_weapons();
|
||||
|
||||
void rebuild_cache();
|
||||
|
||||
private:
|
||||
cache_file m_peds_cache;
|
||||
cache_file m_vehicles_cache;
|
||||
cache_file m_weapons_cache;
|
||||
|
||||
// std::map is free sorting algo
|
||||
ped_map m_peds;
|
||||
vehicle_map m_vehicles;
|
||||
weapon_map m_weapons;
|
||||
|
||||
string_vec m_ped_types;
|
||||
string_vec m_vehicle_classes;
|
||||
string_vec m_weapon_types;
|
||||
|
||||
eGtaDataUpdateState m_update_state;
|
||||
|
||||
private:
|
||||
static constexpr ped_item empty_ped {};
|
||||
static constexpr vehicle_item empty_vehicle {};
|
||||
static constexpr weapon_item empty_weapon {};
|
||||
|
||||
bool load_vehicles(std::filesystem::path path);
|
||||
bool load_peds(std::filesystem::path path);
|
||||
bool load_weapons(std::filesystem::path path);
|
||||
};
|
||||
|
||||
inline gta_data_service* g_gta_data_service{};
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
#include "ped_item.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
ped_item::ped_item()
|
||||
{
|
||||
this->name = "";
|
||||
this->ped_type = "";
|
||||
this->hash = 0;
|
||||
}
|
||||
ped_item::ped_item(nlohmann::json& item_json)
|
||||
{
|
||||
this->name = item_json["Name"];
|
||||
|
||||
this->ped_type = item_json["Pedtype"];
|
||||
std::transform(this->ped_type.begin(), this->ped_type.end(), this->ped_type.begin(), ::toupper);
|
||||
|
||||
this->hash = item_json["Hash"];
|
||||
}
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class ped_item {
|
||||
#pragma pack(push, 4)
|
||||
class ped_item final
|
||||
{
|
||||
public:
|
||||
ped_item();
|
||||
ped_item(nlohmann::json& item_json);
|
||||
|
||||
std::string name;
|
||||
std::string ped_type;
|
||||
Hash hash;
|
||||
char m_name[32];
|
||||
char m_ped_type[16];
|
||||
std::uint32_t m_hash;
|
||||
};
|
||||
}
|
||||
#pragma pack(pop)
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#include "vehicle_item.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
vehicle_item::vehicle_item()
|
||||
{
|
||||
this->name = "";
|
||||
this->display_name = "";
|
||||
this->display_manufacturer = "";
|
||||
this->clazz = "";
|
||||
this->hash = 0;
|
||||
}
|
||||
vehicle_item::vehicle_item(nlohmann::json& item_json)
|
||||
{
|
||||
this->name = item_json["Name"];
|
||||
this->display_name = item_json["Name"];
|
||||
this->display_manufacturer = "";
|
||||
this->clazz = "";
|
||||
this->hash = item_json["Hash"];
|
||||
|
||||
if (!item_json["DisplayName"].is_null())
|
||||
{
|
||||
this->display_name = item_json["DisplayName"];
|
||||
}
|
||||
|
||||
if (!item_json["ManufacturerDisplayName"].is_null())
|
||||
{
|
||||
this->display_manufacturer = item_json["ManufacturerDisplayName"];
|
||||
}
|
||||
else if (!item_json["Manufacturer"].is_null())
|
||||
{
|
||||
this->display_manufacturer = item_json["Manufacturer"];
|
||||
}
|
||||
|
||||
if (!item_json["Class"].is_null())
|
||||
{
|
||||
this->clazz = item_json["Class"];
|
||||
std::transform(this->clazz.begin(), this->clazz.end(), this->clazz.begin(), ::toupper);
|
||||
|
||||
if (this->clazz == "COMPACTS")
|
||||
{
|
||||
this->clazz = "COMPACT";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,16 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class vehicle_item {
|
||||
#pragma pack(push, 4)
|
||||
class vehicle_item final
|
||||
{
|
||||
public:
|
||||
vehicle_item();
|
||||
vehicle_item(nlohmann::json& item_json);
|
||||
|
||||
std::string name;
|
||||
std::string display_name;
|
||||
std::string display_manufacturer;
|
||||
std::string clazz;
|
||||
Hash hash;
|
||||
char m_name[16];
|
||||
char m_display_name[32];
|
||||
char m_display_manufacturer[32];
|
||||
char m_vehicle_class[32];
|
||||
std::uint32_t m_hash;
|
||||
};
|
||||
}
|
||||
#pragma pack(pop)
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
#include "weapon_item.hpp"
|
||||
#include "gta/joaat.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
weapon_item::weapon_item()
|
||||
{
|
||||
this->name = "";
|
||||
this->throwable = false;
|
||||
this->weapon_type = "";
|
||||
|
||||
this->hash = 0;
|
||||
this->reward_hash = 0;
|
||||
this->reward_ammo_hash = 0;
|
||||
}
|
||||
weapon_item::weapon_item(nlohmann::json& item_json)
|
||||
{
|
||||
this->name = item_json["Name"];
|
||||
this->throwable = false;
|
||||
this->weapon_type = "NULL";
|
||||
|
||||
if (
|
||||
item_json.contains("TranslatedLabel") &&
|
||||
item_json["TranslatedLabel"].contains("English") &&
|
||||
!item_json["TranslatedLabel"]["English"].is_null()
|
||||
) {
|
||||
this->name = item_json["TranslatedLabel"]["English"];
|
||||
}
|
||||
|
||||
if (!item_json["Category"].is_null())
|
||||
{
|
||||
this->weapon_type = item_json["Category"];
|
||||
this->weapon_type = this->weapon_type.substr(6);
|
||||
}
|
||||
|
||||
this->hash = item_json["Hash"];
|
||||
this->reward_hash = 0;
|
||||
this->reward_ammo_hash = 0;
|
||||
|
||||
const std::string reward_prefix = "REWARD_";
|
||||
bool is_gun = false;
|
||||
bool is_recharge = false;
|
||||
|
||||
if (item_json.contains("Flags"))
|
||||
{
|
||||
auto flags = item_json["Flags"];
|
||||
|
||||
for (auto& flag : flags)
|
||||
{
|
||||
if (flag == "Gun")
|
||||
{
|
||||
is_gun = true;
|
||||
}
|
||||
else if (flag == "DisplayRechargeTimeHUD")
|
||||
{
|
||||
is_recharge = true;
|
||||
}
|
||||
else if (flag == "Thrown")
|
||||
{
|
||||
this->throwable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->weapon_type == "MELEE" || this->weapon_type == "UNARMED" || is_gun)
|
||||
{
|
||||
this->reward_hash = rage::joaat((reward_prefix + std::string(item_json["Name"])).c_str());
|
||||
|
||||
if (is_gun && !is_recharge)
|
||||
{
|
||||
std::string weapon_id = std::string(item_json["Name"]).substr(7);
|
||||
this->reward_ammo_hash = rage::joaat((reward_prefix + "AMMO_" + weapon_id).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,18 @@
|
||||
#pragma once
|
||||
#include "file_manager/file.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
class weapon_item {
|
||||
#pragma pack(push, 4)
|
||||
class weapon_item final
|
||||
{
|
||||
public:
|
||||
weapon_item();
|
||||
weapon_item(nlohmann::json& item_json);
|
||||
|
||||
std::string name;
|
||||
bool throwable;
|
||||
std::string weapon_type;
|
||||
|
||||
Hash hash;
|
||||
Hash reward_hash;
|
||||
Hash reward_ammo_hash;
|
||||
char m_name[32];
|
||||
char m_display_name[32];
|
||||
char m_weapon_type[16];
|
||||
std::uint32_t m_hash;
|
||||
std::uint32_t m_reward_hash;
|
||||
std::uint32_t m_reward_ammo_hash;
|
||||
bool m_throwable;
|
||||
};
|
||||
}
|
||||
#pragma pack(pop)
|
||||
}
|
216
BigBaseV2/src/services/gta_data/yim_fipackfile.cpp
Normal file
216
BigBaseV2/src/services/gta_data/yim_fipackfile.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
#include "yim_fipackfile.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "gta/fidevice.hpp"
|
||||
#include "script.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
yim_fipackfile::yim_fipackfile(rage::fiPackfile* rpf, const std::string& mount_name)
|
||||
{
|
||||
this->rpf = rpf;
|
||||
this->mount_name = mount_name;
|
||||
}
|
||||
|
||||
static std::vector<std::string> get_non_dlc_mounted_devices_names()
|
||||
{
|
||||
std::vector<std::string> non_dlc_mounted_devices_names;
|
||||
|
||||
uint16_t mounted_devices_len = *g_pointers->m_fidevices_len;
|
||||
if (mounted_devices_len)
|
||||
{
|
||||
auto devices_arr = *(uint64_t*)g_pointers->m_fidevices;
|
||||
uint8_t** current_device_mount_name_ptr = *(unsigned __int8***)g_pointers->m_fidevices;
|
||||
auto device_i = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
non_dlc_mounted_devices_names.push_back(*(const char**)current_device_mount_name_ptr);
|
||||
|
||||
++device_i;
|
||||
current_device_mount_name_ptr += 4;
|
||||
if (device_i >= mounted_devices_len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return non_dlc_mounted_devices_names;
|
||||
}
|
||||
|
||||
static int ends_with(const char* str, const char* suffix)
|
||||
{
|
||||
if (!str || !suffix)
|
||||
return 0;
|
||||
size_t lenstr = strlen(str);
|
||||
size_t lensuffix = strlen(suffix);
|
||||
if (lensuffix > lenstr)
|
||||
return 0;
|
||||
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
|
||||
}
|
||||
|
||||
void yim_fipackfile::for_each_fipackfile(std::function<size_t(yim_fipackfile& rpf_wrapper)> cb)
|
||||
{
|
||||
// the idea is to reuse existing mount points as much as possible because
|
||||
// even when mounting / unmounting properly you'll get file errors
|
||||
// and crashes if the rpf file was already mounted
|
||||
|
||||
// iterate the fidevice array which contains devices that are currently mounted
|
||||
// the dlc devices are in another array
|
||||
const auto non_dlc_mounted_devices_names = get_non_dlc_mounted_devices_names();
|
||||
|
||||
// for not hanging the game too much
|
||||
constexpr auto yield_increment = 80;
|
||||
|
||||
auto i = 1;
|
||||
while (g_pointers->m_fipackfile_instances[i])
|
||||
{
|
||||
auto* rpf = g_pointers->m_fipackfile_instances[i];
|
||||
|
||||
// its hard coded in the binary?
|
||||
if (++i >= 3672)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
yim_fipackfile rpf_wrapper = yim_fipackfile(rpf, default_mount_name);
|
||||
|
||||
auto already_mounted = false;
|
||||
for (const auto& non_dlc_mounted_device_name : non_dlc_mounted_devices_names)
|
||||
{
|
||||
auto* non_dlc_mounted_device = rage::fiDevice::GetDevice(non_dlc_mounted_device_name.c_str(), true);
|
||||
|
||||
if (rpf == non_dlc_mounted_device)
|
||||
{
|
||||
rpf_wrapper.mount_name = non_dlc_mounted_device_name;
|
||||
already_mounted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!already_mounted)
|
||||
{
|
||||
size_t acc = 0;
|
||||
|
||||
rpf_wrapper.mount_name = "memory:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "memory:";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "dlc";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "dlc:";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "dlc:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "dlcpacks:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "common:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "commoncrc:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "update:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "update2:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "platform:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "platformcrc:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
rpf_wrapper.mount_name = "gamecache:/";
|
||||
acc += cb(rpf_wrapper);
|
||||
|
||||
// if we got nothing with those mount points for this rpf, mount it
|
||||
if (!acc)
|
||||
{
|
||||
rpf_wrapper.mount_name = default_mount_name;
|
||||
rpf->Mount(default_mount_name);
|
||||
|
||||
cb(rpf_wrapper);
|
||||
|
||||
g_pointers->m_fipackfile_unmount(default_mount_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cb(rpf_wrapper);
|
||||
}
|
||||
|
||||
if (i % yield_increment == 0)
|
||||
script::get_current()->yield();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::filesystem::path> yim_fipackfile::get_file_paths(std::string parent)
|
||||
{
|
||||
std::vector<std::filesystem::path> file_paths;
|
||||
if (parent.empty())
|
||||
parent = mount_name;
|
||||
|
||||
std::vector<std::string> directories;
|
||||
|
||||
rage::fiFindData findData = { 0 };
|
||||
auto handlef = rpf->FindFirst(parent.c_str(), &findData);
|
||||
if (handlef != -1)
|
||||
{
|
||||
do
|
||||
{
|
||||
std::string fn = std::string(parent.c_str()) + std::string("/") + std::string(findData.fileName);
|
||||
|
||||
if (findData.fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
directories.push_back(fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
file_paths.push_back(fn);
|
||||
}
|
||||
} while (rpf->FindNext(handlef, &findData));
|
||||
|
||||
rpf->FindClose(handlef);
|
||||
}
|
||||
|
||||
for (auto& directory : directories)
|
||||
{
|
||||
auto files = get_file_paths(directory);
|
||||
|
||||
file_paths.insert(file_paths.end(), files.begin(), files.end());
|
||||
}
|
||||
|
||||
return file_paths;
|
||||
}
|
||||
|
||||
void yim_fipackfile::read_file(const std::filesystem::path& path, file_contents_callback&& cb)
|
||||
{
|
||||
if (const auto handle = rpf->Open(path.string().c_str(), true); handle != -1)
|
||||
{
|
||||
const auto data_length = rpf->GetFileLength(handle);
|
||||
const auto file_content = std::make_unique<std::uint8_t[]>(data_length);
|
||||
|
||||
rpf->ReadFull(handle, file_content.get(), data_length);
|
||||
|
||||
cb(file_content, data_length);
|
||||
|
||||
rpf->Close(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void yim_fipackfile::read_xml_file(const std::filesystem::path& path, std::function<void(pugi::xml_document& doc)> cb)
|
||||
{
|
||||
read_file(path, [&cb](const std::unique_ptr<std::uint8_t[]>& file_content, const int data_size)
|
||||
{
|
||||
if (pugi::xml_document doc; doc.load_buffer(file_content.get(), data_size).status == pugi::xml_parse_status::status_ok)
|
||||
{
|
||||
cb(doc);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
27
BigBaseV2/src/services/gta_data/yim_fipackfile.hpp
Normal file
27
BigBaseV2/src/services/gta_data/yim_fipackfile.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
using file_contents_callback = std::function<void(const std::unique_ptr<std::uint8_t[]>& file_content, const int data_size)>;
|
||||
class yim_fipackfile
|
||||
{
|
||||
static constexpr auto default_mount_name = "yimM:/";
|
||||
|
||||
rage::fiPackfile* rpf;
|
||||
std::string mount_name;
|
||||
|
||||
public:
|
||||
explicit yim_fipackfile(rage::fiPackfile* rpf, const std::string& mount_name);
|
||||
|
||||
static void for_each_fipackfile(std::function<size_t(yim_fipackfile& rpf_wrapper)> cb);
|
||||
std::vector<std::filesystem::path> get_file_paths(std::string parent = {});
|
||||
|
||||
void read_file(const std::filesystem::path& path, file_contents_callback&& cb);
|
||||
|
||||
void read_xml_file(const std::filesystem::path& path, std::function<void(pugi::xml_document& doc)> cb);
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include "pickup_service.hpp"
|
||||
#include "gta/joaat.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "script.hpp"
|
||||
#include "services/gta_data/gta_data_service.hpp"
|
||||
@ -37,11 +38,11 @@ namespace big
|
||||
|
||||
void pickup_service::give_ammo(const int targets) const
|
||||
{
|
||||
for (const auto& weapon : g_gta_data_service->get_weapon_arr())
|
||||
for (const auto& [_, weapon] : g_gta_data_service->weapons())
|
||||
{
|
||||
if (weapon.reward_ammo_hash != 0 || weapon.throwable)
|
||||
if (weapon.m_reward_ammo_hash != 0 || weapon.m_throwable)
|
||||
{
|
||||
g_pointers->m_give_pickup_rewards(targets, weapon.reward_ammo_hash);
|
||||
g_pointers->m_give_pickup_rewards(targets, weapon.m_reward_ammo_hash);
|
||||
script::get_current()->yield(20ms);
|
||||
}
|
||||
}
|
||||
@ -63,11 +64,11 @@ namespace big
|
||||
|
||||
void pickup_service::give_weapons(const int targets) const
|
||||
{
|
||||
for (const auto& weapon : g_gta_data_service->get_weapon_arr())
|
||||
for (const auto& [_, weapon] : g_gta_data_service->weapons())
|
||||
{
|
||||
if (weapon.reward_hash != 0)
|
||||
if (weapon.m_reward_hash != 0)
|
||||
{
|
||||
g_pointers->m_give_pickup_rewards(targets, weapon.reward_hash);
|
||||
g_pointers->m_give_pickup_rewards(targets, weapon.m_reward_hash);
|
||||
script::get_current()->yield(20ms);
|
||||
}
|
||||
}
|
||||
|
@ -6,23 +6,26 @@
|
||||
|
||||
namespace big::session
|
||||
{
|
||||
void join_type(SessionType session)
|
||||
inline void join_type(eSessionType session)
|
||||
{
|
||||
*script_global(2726795).as<int*>() = (session.id == eSessionType::SC_TV ? 1 : 0); // If SC TV Then Enable Spectator Mode
|
||||
*script_global(2726795).as<int*>() = (session == eSessionType::SC_TV ? 1 : 0); // If SC TV Then Enable Spectator Mode
|
||||
|
||||
if (session.id == eSessionType::LEAVE_ONLINE)
|
||||
if (session == eSessionType::LEAVE_ONLINE)
|
||||
*script_global(1574589).at(2).as<int*>() = -1;
|
||||
else
|
||||
*script_global(1575015).as<int*>() = (int)session.id;
|
||||
*script_global(1575015).as<int*>() = (int)session;
|
||||
|
||||
*script_global(1574589).as<int*>() = 1;
|
||||
script::get_current()->yield(200ms);
|
||||
*script_global(1574589).as<int*>() = 0;
|
||||
}
|
||||
|
||||
static constexpr char const* weathers[] = { "EXTRASUNNY", "CLEAR", "CLOUDS", "SMOG", "FOGGY", "OVERCAST", "RAIN", "THUNDER", "CLEARING", "NEUTRAL", "SNOW", "BLIZZARD", "SNOWLIGHT", "XMAS", "HALLOWEEN" };
|
||||
|
||||
void local_weather()
|
||||
static constexpr char const* weathers[] = {
|
||||
"EXTRASUNNY", "CLEAR", "CLOUDS", "SMOG",
|
||||
"FOGGY", "OVERCAST", "RAIN", "THUNDER",
|
||||
"CLEARING", "NEUTRAL", "SNOW", "BLIZZARD",
|
||||
"SNOWLIGHT", "XMAS", "HALLOWEEN" };
|
||||
inline void local_weather()
|
||||
{
|
||||
MISC::CLEAR_OVERRIDE_WEATHER();
|
||||
|
||||
|
@ -11,8 +11,9 @@ namespace big
|
||||
{
|
||||
for (const auto& session_type : sessions)
|
||||
{
|
||||
components::selectable(session_type.name, false, [session_type] {
|
||||
session::join_type(session_type);
|
||||
components::selectable(session_type.name, false, [&session_type]
|
||||
{
|
||||
session::join_type(session_type.id);
|
||||
});
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
@ -32,7 +33,8 @@ namespace big
|
||||
}
|
||||
if (ImGui::TreeNode("Local Weather"))
|
||||
{
|
||||
components::button("Clear Override", [] {
|
||||
components::button("Clear Override", []
|
||||
{
|
||||
MISC::CLEAR_OVERRIDE_WEATHER();
|
||||
});
|
||||
|
||||
|
@ -72,24 +72,26 @@ namespace big
|
||||
|
||||
ImGui::Checkbox("No Spread", &g->weapons.no_spread);
|
||||
|
||||
components::button("Get All Weapons", [] {
|
||||
for (auto const& weapon : g_gta_data_service->get_weapon_arr())
|
||||
components::button("Get All Weapons", []
|
||||
{
|
||||
for (const auto& [_, weapon] : g_gta_data_service->weapons())
|
||||
{
|
||||
WEAPON::GIVE_DELAYED_WEAPON_TO_PED(self::ped, weapon.hash, 9999, false);
|
||||
WEAPON::GIVE_DELAYED_WEAPON_TO_PED(self::ped, weapon.m_hash, 9999, false);
|
||||
}
|
||||
|
||||
constexpr auto parachute_hash = RAGE_JOAAT("GADGET_PARACHUTE");
|
||||
WEAPON::GIVE_DELAYED_WEAPON_TO_PED(self::ped, parachute_hash, 0, true);
|
||||
});
|
||||
});
|
||||
ImGui::SameLine();
|
||||
components::button("Remove Current Weapon", [] {
|
||||
components::button("Remove Current Weapon", []
|
||||
{
|
||||
Hash weaponHash;
|
||||
WEAPON::GET_CURRENT_PED_WEAPON(self::ped, &weaponHash, 1);
|
||||
if (weaponHash != RAGE_JOAAT("WEAPON_UNARMED"))
|
||||
{
|
||||
WEAPON::REMOVE_WEAPON_FROM_PED(self::ped, weaponHash);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ImGui::SliderFloat("Damage Multiplier", &g->weapons.increased_damage, 1.f, 10.f, "%.1f");
|
||||
|
||||
|
@ -51,7 +51,7 @@ namespace big
|
||||
|
||||
|
||||
static int selected_class = -1;
|
||||
auto class_arr = g_gta_data_service->get_vehicle_class_arr();
|
||||
const auto& class_arr = g_gta_data_service->vehicle_classes();
|
||||
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
if (ImGui::BeginCombo("Vehicle Class", selected_class == -1 ? "ALL" : class_arr[selected_class].c_str()))
|
||||
@ -99,16 +99,16 @@ namespace big
|
||||
{
|
||||
const auto& label = it.first;
|
||||
const auto& personal_veh = it.second;
|
||||
auto item = g_gta_data_service->find_vehicle_by_hash(personal_veh->get_hash());
|
||||
const auto& item = g_gta_data_service->vehicle_by_hash(personal_veh->get_hash());
|
||||
|
||||
std::string clazz = item.clazz;
|
||||
std::string vehicle_class = item.m_vehicle_class;
|
||||
std::string display_name = label;
|
||||
std::string display_manufacturer = item.display_manufacturer;
|
||||
std::string display_manufacturer = item.m_display_manufacturer;
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
|
||||
if ((
|
||||
selected_class == -1 || class_arr[selected_class] == clazz
|
||||
selected_class == -1 || class_arr[selected_class] == vehicle_class
|
||||
) && (
|
||||
display_name.find(lower_search) != std::string::npos ||
|
||||
display_manufacturer.find(lower_search) != std::string::npos
|
||||
|
@ -33,7 +33,7 @@ namespace big
|
||||
|
||||
|
||||
static int selected_class = -1;
|
||||
auto class_arr = g_gta_data_service->get_vehicle_class_arr();
|
||||
const auto& class_arr = g_gta_data_service->vehicle_classes();
|
||||
|
||||
ImGui::SetNextItemWidth(300.f);
|
||||
if (ImGui::BeginCombo("Vehicle Class", selected_class == -1 ? "ALL" : class_arr[selected_class].c_str()))
|
||||
@ -78,9 +78,9 @@ namespace big
|
||||
|
||||
if (veh_hash)
|
||||
{
|
||||
auto item = g_gta_data_service->find_vehicle_by_hash(veh_hash);
|
||||
const auto& item = g_gta_data_service->vehicle_by_hash(veh_hash);
|
||||
|
||||
components::selectable("Current Vehicle [" + item.display_name + "]", false, [] {
|
||||
components::selectable(fmt::format("Current Vehicle [{}]", item.m_display_name), false, [] {
|
||||
if (self::veh)
|
||||
{
|
||||
Vector3 spawn_location = vehicle::get_spawn_location(g->spawn_vehicle.spawn_inside);
|
||||
@ -129,17 +129,19 @@ namespace big
|
||||
}
|
||||
}
|
||||
|
||||
auto item_arr = g_gta_data_service->get_vehicle_arr();
|
||||
|
||||
const auto& item_arr = g_gta_data_service->vehicles();
|
||||
if (item_arr.size() > 0)
|
||||
{
|
||||
std::string lower_search = search;
|
||||
std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower);
|
||||
|
||||
for (auto& item : item_arr) {
|
||||
std::string display_name = item.display_name;
|
||||
std::string display_manufacturer = item.display_manufacturer;
|
||||
std::string clazz = item.clazz;
|
||||
for (auto& item : item_arr)
|
||||
{
|
||||
const auto& vehicle = item.second;
|
||||
|
||||
std::string display_name = vehicle.m_display_name;
|
||||
std::string display_manufacturer = vehicle.m_display_manufacturer;
|
||||
std::string clazz = vehicle.m_vehicle_class;
|
||||
|
||||
std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower);
|
||||
std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower);
|
||||
@ -150,13 +152,13 @@ namespace big
|
||||
display_name.find(lower_search) != std::string::npos ||
|
||||
display_manufacturer.find(lower_search) != std::string::npos
|
||||
)) {
|
||||
ImGui::PushID(item.hash);
|
||||
components::selectable(item.display_name, false, [item] {
|
||||
ImGui::PushID(vehicle.m_hash);
|
||||
components::selectable(vehicle.m_display_name, false, [&vehicle]
|
||||
{
|
||||
const auto spawn_location = vehicle::get_spawn_location(g->spawn_vehicle.spawn_inside);
|
||||
const auto spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
Vector3 spawn_location = vehicle::get_spawn_location(g->spawn_vehicle.spawn_inside);
|
||||
float spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
const Vehicle veh = vehicle::spawn(item.hash, spawn_location, spawn_heading);
|
||||
const auto veh = vehicle::spawn(vehicle.m_hash, spawn_location, spawn_heading);
|
||||
|
||||
if (veh == 0)
|
||||
{
|
||||
@ -187,7 +189,7 @@ namespace big
|
||||
}
|
||||
else if (ImGui::IsItemHovered())
|
||||
{
|
||||
g_model_preview_service->show_vehicle(item.hash, g->spawn_vehicle.spawn_maxed);
|
||||
g_model_preview_service->show_vehicle(vehicle.m_hash, g->spawn_vehicle.spawn_maxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,11 +44,16 @@ namespace big
|
||||
static void players();
|
||||
static void weapons();
|
||||
static void context_menu();
|
||||
static void gta_data();
|
||||
|
||||
// later calls will be drawn over earlier calls
|
||||
static void always()
|
||||
{
|
||||
esp::draw();
|
||||
context_menu();
|
||||
|
||||
gta_data();
|
||||
|
||||
notifications();
|
||||
}
|
||||
};
|
||||
|
75
BigBaseV2/src/views/view_gta_data.cpp
Normal file
75
BigBaseV2/src/views/view_gta_data.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "view.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/gta_data/gta_data_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
void view::gta_data()
|
||||
{
|
||||
if (!g_gta_data_service)
|
||||
return;
|
||||
|
||||
if (g_gta_data_service->cache_needs_update())
|
||||
{
|
||||
g_gui.m_opened = true;
|
||||
ImGui::OpenPopup("Game Cache");
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(800, 0), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::BeginPopupModal("Game Cache"))
|
||||
{
|
||||
switch (g_gta_data_service->state())
|
||||
{
|
||||
case eGtaDataUpdateState::NEEDS_UPDATE:
|
||||
{
|
||||
ImGui::Text("YimMenu requires a rebuild of the game cache. This may take up to one minute to generate.");
|
||||
|
||||
if (*g_pointers->m_is_session_started)
|
||||
{
|
||||
if (ImGui::Button("Update Cache"))
|
||||
{
|
||||
g_gta_data_service->update_now();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextWrapped("You are currently in single player, you can force build the cache in single player but risk crashing when going into multiplayer or load online and cache.");
|
||||
|
||||
if (ImGui::Button("I don't care, update in single player!"))
|
||||
{
|
||||
g_gta_data_service->update_now();
|
||||
}
|
||||
|
||||
if (ImGui::Button("Update cache in online."))
|
||||
{
|
||||
g_gta_data_service->update_in_online();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case eGtaDataUpdateState::WAITING_FOR_ONLINE:
|
||||
{
|
||||
ImGui::Text("Waiting for online to start cache update...");
|
||||
|
||||
break;
|
||||
}
|
||||
case eGtaDataUpdateState::UPDATING:
|
||||
{
|
||||
ImGui::Text("Updating cache, please wait...");
|
||||
|
||||
break;
|
||||
}
|
||||
case eGtaDataUpdateState::IDLE:
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
@ -17,9 +17,9 @@
|
||||
namespace big
|
||||
{
|
||||
Ped spawn_ped_at_location(
|
||||
const int selected_ped_type,
|
||||
const char* ped_model_buf,
|
||||
const Player selected_ped_player_id,
|
||||
const int selected_ped_type,
|
||||
const char* ped_model_buf,
|
||||
const Player selected_ped_player_id,
|
||||
const Player selected_ped_for_player_id,
|
||||
const bool is_bodyguard
|
||||
) {
|
||||
@ -114,8 +114,8 @@ namespace big
|
||||
|
||||
|
||||
void spawn_ped_give_weapon(
|
||||
const Ped ped,
|
||||
const int selected_ped_weapon_type,
|
||||
const Ped ped,
|
||||
const int selected_ped_weapon_type,
|
||||
const Hash selected_ped_weapon_hash
|
||||
) {
|
||||
if (selected_ped_weapon_type == SPAWN_PED_NO_WEAPONS)
|
||||
@ -123,18 +123,18 @@ namespace big
|
||||
return;
|
||||
}
|
||||
|
||||
auto weapon_type_arr = g_gta_data_service->get_weapon_type_arr();
|
||||
for (auto& weapon : g_gta_data_service->get_weapon_arr())
|
||||
const auto& weapon_type_arr = g_gta_data_service->weapon_types();
|
||||
for (auto& [_, weapon] : g_gta_data_service->weapons())
|
||||
{
|
||||
if (
|
||||
selected_ped_weapon_type == SPAWN_PED_ALL_WEAPONS ||
|
||||
weapon.weapon_type == weapon_type_arr[selected_ped_weapon_type]
|
||||
weapon.m_weapon_type == weapon_type_arr[selected_ped_weapon_type]
|
||||
) {
|
||||
if (
|
||||
selected_ped_weapon_hash == 0 ||
|
||||
weapon.hash == selected_ped_weapon_hash
|
||||
weapon.m_hash == selected_ped_weapon_hash
|
||||
) {
|
||||
WEAPON::GIVE_WEAPON_TO_PED(ped, weapon.hash, 9999, false, selected_ped_weapon_hash != 0);
|
||||
WEAPON::GIVE_WEAPON_TO_PED(ped, weapon.m_hash, 9999, false, selected_ped_weapon_hash != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -147,14 +147,14 @@ namespace big
|
||||
static char ped_model_buf[64];
|
||||
static Player selected_ped_player_id = -1;
|
||||
|
||||
auto ped_type_arr = g_gta_data_service->get_ped_type_arr();
|
||||
auto ped_arr = g_gta_data_service->get_ped_arr();
|
||||
auto ped_type_arr = g_gta_data_service->ped_types();
|
||||
auto ped_arr = g_gta_data_service->peds();
|
||||
|
||||
|
||||
static int selected_ped_weapon_type = SPAWN_PED_ALL_WEAPONS;
|
||||
static Hash selected_ped_weapon_hash = 0;
|
||||
auto weapon_type_arr = g_gta_data_service->get_weapon_type_arr();
|
||||
auto weapon_arr = g_gta_data_service->get_weapon_arr();
|
||||
auto weapon_type_arr = g_gta_data_service->weapon_types();
|
||||
auto weapon_arr = g_gta_data_service->weapons();
|
||||
|
||||
static Player selected_ped_for_player_id = -1;
|
||||
auto player_arr = g_player_service->players();
|
||||
@ -186,9 +186,9 @@ namespace big
|
||||
|
||||
ImGui::SetNextItemWidth(160.f);
|
||||
if (ImGui::BeginCombo(
|
||||
"##ped_type",
|
||||
selected_ped_type == -1 ? "ALL" :
|
||||
selected_ped_type == -2 ? "ONLINE PLAYER" :
|
||||
"##ped_type",
|
||||
selected_ped_type == -1 ? "ALL" :
|
||||
selected_ped_type == -2 ? "ONLINE PLAYER" :
|
||||
ped_type_arr[selected_ped_type].c_str()
|
||||
)) {
|
||||
|
||||
@ -312,8 +312,8 @@ namespace big
|
||||
|
||||
ImGui::SetNextItemWidth(240.f);
|
||||
components::input_text_with_hint(
|
||||
"##ped_model_name", "Model Name",
|
||||
ped_model_buf, sizeof(ped_model_buf), ImGuiInputTextFlags_EnterReturnsTrue,
|
||||
"##ped_model_name", "Model Name",
|
||||
ped_model_buf, sizeof(ped_model_buf), ImGuiInputTextFlags_EnterReturnsTrue,
|
||||
[] {
|
||||
ped_model_dropdown_open = false;
|
||||
}
|
||||
@ -345,10 +345,10 @@ namespace big
|
||||
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
|
||||
ped_model_dropdown_focused |= ImGui::IsWindowFocused();
|
||||
|
||||
for (auto& item : ped_arr)
|
||||
for (const auto& [_, item] : ped_arr)
|
||||
{
|
||||
std::string ped_type = item.ped_type;
|
||||
std::string name = item.name;
|
||||
std::string ped_type = item.m_ped_type;
|
||||
std::string name = item.m_name;
|
||||
|
||||
std::transform(name.begin(), name.end(), name.begin(), tolower);
|
||||
|
||||
@ -359,12 +359,12 @@ namespace big
|
||||
)) {
|
||||
|
||||
bool selectable_highlighted = lower_search == name;
|
||||
bool selectable_clicked = ImGui::Selectable(item.name.c_str(), selectable_highlighted);
|
||||
bool selectable_clicked = ImGui::Selectable(item.m_name, selectable_highlighted);
|
||||
ped_model_dropdown_focused |= ImGui::IsItemFocused();
|
||||
|
||||
if (selectable_clicked)
|
||||
{
|
||||
strncpy(ped_model_buf, item.name.c_str(), 64);
|
||||
strncpy(ped_model_buf, item.m_name, 64);
|
||||
ped_model_dropdown_open = false;
|
||||
ped_model_dropdown_focused = false;
|
||||
}
|
||||
@ -377,7 +377,7 @@ namespace big
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
item_hovered = true;
|
||||
g_model_preview_service->show_ped(item.hash);
|
||||
g_model_preview_service->show_ped(item.m_hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -405,9 +405,9 @@ namespace big
|
||||
|
||||
ImGui::SetNextItemWidth(160.f);
|
||||
if (ImGui::BeginCombo(
|
||||
"##ped_weapon_type",
|
||||
selected_ped_weapon_type == SPAWN_PED_ALL_WEAPONS ?
|
||||
"ALL" :
|
||||
"##ped_weapon_type",
|
||||
selected_ped_weapon_type == SPAWN_PED_ALL_WEAPONS ?
|
||||
"ALL" :
|
||||
selected_ped_weapon_type == SPAWN_PED_NO_WEAPONS ?
|
||||
"NO WEAPONS" :
|
||||
weapon_type_arr[selected_ped_weapon_type].c_str()
|
||||
@ -459,12 +459,12 @@ namespace big
|
||||
|
||||
ImGui::SetNextItemWidth(240.f);
|
||||
if (ImGui::BeginCombo(
|
||||
"##ped_weapon",
|
||||
"##ped_weapon",
|
||||
selected_ped_weapon_type == SPAWN_PED_NO_WEAPONS ?
|
||||
"NO WEAPONS" :
|
||||
selected_ped_weapon_hash == 0 ?
|
||||
"ALL" :
|
||||
g_gta_data_service->find_weapon_by_hash(selected_ped_weapon_hash).name.c_str()
|
||||
selected_ped_weapon_hash == 0 ?
|
||||
"ALL" :
|
||||
g_gta_data_service->weapon_by_hash(selected_ped_weapon_hash).m_display_name
|
||||
)) {
|
||||
if (selected_ped_weapon_type != SPAWN_PED_NO_WEAPONS)
|
||||
{
|
||||
@ -478,19 +478,19 @@ namespace big
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
||||
for (auto& weapon : weapon_arr)
|
||||
for (const auto& [_, weapon] : weapon_arr)
|
||||
{
|
||||
if (
|
||||
selected_ped_weapon_type == SPAWN_PED_ALL_WEAPONS ||
|
||||
weapon.weapon_type == weapon_type_arr[selected_ped_weapon_type]
|
||||
weapon.m_weapon_type == weapon_type_arr[selected_ped_weapon_type]
|
||||
) {
|
||||
if (ImGui::Selectable(weapon.name.c_str(), weapon.hash == selected_ped_weapon_hash))
|
||||
if (ImGui::Selectable(weapon.m_display_name, weapon.m_hash == selected_ped_weapon_hash))
|
||||
{
|
||||
selected_ped_weapon_hash = weapon.hash;
|
||||
selected_ped_weapon_hash = weapon.m_hash;
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_ped_weapon_hash == weapon.hash)
|
||||
if (selected_ped_weapon_hash == weapon.m_hash)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
|
28
premake5.lua
28
premake5.lua
@ -179,6 +179,28 @@ workspace "BigBaseV2"
|
||||
|
||||
DeclareMSVCOptions()
|
||||
DeclareDebugOptions()
|
||||
|
||||
project "pugixml"
|
||||
location "vendor/%{prj.name}"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
targetdir ("bin/lib/" .. outputdir)
|
||||
objdir ("bin/lib/int/" .. outputdir .. "/%{prj.name}")
|
||||
|
||||
files
|
||||
{
|
||||
"vendor/%{prj.name}/src/**.cpp",
|
||||
"vendor/%{prj.name}/src/**.hpp"
|
||||
}
|
||||
|
||||
includedirs
|
||||
{
|
||||
"vendor/%{prj.name}/src/"
|
||||
}
|
||||
|
||||
DeclareMSVCOptions()
|
||||
DeclareDebugOptions()
|
||||
|
||||
project "BigBaseV2"
|
||||
location "BigBaseV2"
|
||||
@ -207,7 +229,8 @@ workspace "BigBaseV2"
|
||||
"vendor/GTAV-Classes",
|
||||
"vendor/ImGui",
|
||||
"vendor/json/single_include",
|
||||
"vendor/MinHook/include"
|
||||
"vendor/MinHook/include",
|
||||
"vendor/pugixml/src"
|
||||
}
|
||||
|
||||
libdirs
|
||||
@ -220,7 +243,8 @@ workspace "BigBaseV2"
|
||||
"fmtlib",
|
||||
"g3log",
|
||||
"ImGui",
|
||||
"MinHook"
|
||||
"MinHook",
|
||||
"pugixml"
|
||||
}
|
||||
|
||||
pchheader "common.hpp"
|
||||
|
1
vendor/pugixml
vendored
Submodule
1
vendor/pugixml
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 86c91051541d18a0d24b837a866cf0306fc8db1a
|
Reference in New Issue
Block a user