Script VM classes (#60)

* feat(Script): Ported BBv2 script classes
* fix: Change hard tab indents to 4 width space indents
This commit is contained in:
Yimura 2022-11-08 22:11:50 +01:00 committed by GitHub
parent 12919a46ff
commit d81f392e61
64 changed files with 1963 additions and 1320 deletions

View File

@ -6,7 +6,6 @@ namespace rage
{
class phArchetype
{
public:
char pad_0000[32]; //0x0000
class phBound* m_bound; //0x0020
char pad_0028[16]; //0x0028
@ -15,7 +14,6 @@ namespace rage
class phArchetypePhys : public phArchetype
{
public:
char pad_0038[28]; //0x0028
float m_water_collision; //0x0054
char pad_0058[40]; //0x0058

25
rage/sysMemAllocator.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <cstddef>
namespace rage
{
class sysMemAllocator
{
public:
virtual ~sysMemAllocator() = 0;
virtual void SetQuitOnFail(bool) = 0;
virtual void* Allocate(std::size_t size, std::size_t align, int subAllocator) = 0;
virtual void* TryAllocate(std::size_t size, std::size_t align, int subAllocator) = 0;
virtual void Free(void* pointer) = 0;
virtual void TryFree(void* pointer) = 0;
virtual void Resize(void* pointer, std::size_t size) = 0;
virtual sysMemAllocator* GetAllocator(int allocator) const = 0;
virtual sysMemAllocator* GetAllocator(int allocator) = 0;
virtual sysMemAllocator* GetPointerOwner(void* pointer) = 0;
virtual std::size_t GetSize(void* pointer) const = 0;
virtual std::size_t GetMemoryUsed(int memoryBucket) = 0;
virtual std::size_t GetMemoryAvailable() = 0;
};
}

0
script/GtaThread.hpp Normal file
View File

22
script/dataList.hpp Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "../base/datBase.hpp"
namespace rage
{
template <typename T, typename Base = datBase>
class atDNode : public Base
{
public:
T m_data;
void *m_unk;
atDNode<T, Base> *m_next;
};
template <typename Node>
class atDList
{
public:
Node *m_head;
Node *m_tail;
};
}

View File

@ -0,0 +1,60 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <utility>
namespace rage
{
using scrNativeHash = std::int64_t;
using scrNativePair = std::pair<scrNativeHash, scrNativeHash>;
class scrNativeCallContext
{
public:
void reset()
{
m_arg_count = 0;
m_data_count = 0;
}
template <typename T>
void push_arg(T &&value)
{
static_assert(sizeof(T) <= sizeof(std::uint64_t));
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<T>>*>(reinterpret_cast<std::uint64_t*>(m_args) + (m_arg_count++)) = std::forward<T>(value);
}
template <typename T>
T &get_arg(std::size_t index)
{
static_assert(sizeof(T) <= sizeof(std::uint64_t));
return *reinterpret_cast<T*>(reinterpret_cast<std::uint64_t*>(m_args) + index);
}
template <typename T>
void set_arg(std::size_t index, T &&value)
{
static_assert(sizeof(T) <= sizeof(std::uint64_t));
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<T>>*>(reinterpret_cast<std::uint64_t*>(m_args) + index) = std::forward<T>(value);
}
template <typename T>
T *get_return_value()
{
return reinterpret_cast<T*>(m_return_value);
}
template <typename T>
void set_return_value(T &&value)
{
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<T>>*>(m_return_value) = std::forward<T>(value);
}
protected:
void *m_return_value;
std::uint32_t m_arg_count;
void *m_args;
std::int32_t m_data_count;
std::uint32_t m_data[48];
};
static_assert(sizeof(scrNativeCallContext) == 0xE0);
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <cstdint>
namespace rage
{
class scrNativeRegistration
{
public:
uint64_t m_next_registration1;
uint64_t m_next_registration2;
void* m_handlers[7];
uint32_t m_num_entries1;
uint32_t m_num_entries2;
uint64_t m_hashes;
scrNativeRegistration* get_next_registration() {
std::uintptr_t result;
auto nextReg = uintptr_t(&m_next_registration1);
auto newReg = nextReg ^ m_next_registration2;
auto charTableOfRegs = (char*)&result - nextReg;
for (auto i = 0; i < 3; i++) {
*(std::uint32_t*)&charTableOfRegs[nextReg] = static_cast<std::uint32_t>(newReg) ^ *(std::uint32_t*)nextReg;
nextReg += 4;
}
return reinterpret_cast<scrNativeRegistration*>(result);
}
std::uint32_t get_num_entries() {
return static_cast<std::uint32_t>(((std::uintptr_t)&m_num_entries1) ^ m_num_entries1 ^ m_num_entries2);
}
std::uint64_t get_hash(std::uint32_t index) {
auto nativeAddress = 16 * index + std::uintptr_t(&m_next_registration1) + 0x54;
std::uint64_t result;
auto charTableOfRegs = (char*)&result - nativeAddress;
auto addressIndex = nativeAddress ^ *(std::uint32_t*)(nativeAddress + 8);
for (auto i = 0; i < 3; i++) {
*(std::uint32_t*)&charTableOfRegs[nativeAddress] = static_cast<std::uint32_t>(addressIndex ^ *(std::uint32_t*)(nativeAddress));
nativeAddress += 4;
}
return result;
}
};
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
#include "scrNativeRegistration.hpp"
#pragma pack(push, 1)
namespace rage
{
class scrNativeRegistrationTable
{
scrNativeRegistration *m_entries[0xFF];
std::uint32_t m_unk;
bool m_initialized;
};
}
#pragma pack(pop)

100
script/scrProgram.hpp Normal file
View File

@ -0,0 +1,100 @@
#pragma once
#include <cstdint>
#include "../base/pgBase.hpp"
#pragma pack(push, 1)
namespace rage
{
class scrProgram : public pgBase
{
public:
std::uint8_t** m_code_blocks; // 0x10
std::uint32_t m_hash; // 0x18
std::uint32_t m_code_size; // 0x1C
std::uint32_t m_arg_count; // 0x20
std::uint32_t m_local_count; // 0x24
std::uint32_t m_global_count; // 0x28
std::uint32_t m_native_count; // 0x2C
void *m_local_data; // 0x30
std::int64_t **m_global_data; // 0x38
void **m_native_entrypoints; // 0x40
char m_padding6[0x10]; // 0x48
std::uint32_t m_name_hash; // 0x58
char m_padding7[0x04]; // 0x5C
const char* m_name; // 0x60
const char** m_strings_data; // 0x68
std::uint32_t m_strings_count; // 0x70
char m_padding8[0x0C]; // 0x74
bool is_valid() const
{
return m_code_size != 0;
}
std::uint32_t get_num_code_pages() const
{
return (m_code_size + 0x3FFF) >> 14;
}
std::uint32_t get_code_page_size(std::uint32_t page) const
{
auto num = get_num_code_pages();
if (page < num)
{
if (page == num - 1)
return m_code_size & 0x3FFF;
return 0x4000;
}
return 0;
}
std::uint32_t get_full_code_size() const
{
auto numPages = get_num_code_pages();
if (!numPages)
return 0;
if (numPages == 1)
--numPages;
return (numPages * 0x4000) + (m_code_size & 0x3FFF);
}
std::uint8_t* get_code_page(std::uint32_t page) const
{
return m_code_blocks[page];
}
std::uint8_t* get_code_address(std::uint32_t index) const
{
if (index < m_code_size)
return &m_code_blocks[index >> 14][index & 0x3FFF];
return nullptr;
}
const char* get_string(std::uint32_t index) const
{
if (index < m_strings_count)
return &m_strings_data[index >> 14][index & 0x3FFF];
return nullptr;
}
void** get_address_of_native_entrypoint(void* entrypoint)
{
for (std::uint32_t i = 0; i < m_native_count; ++i)
{
if (m_native_entrypoints[i] == entrypoint)
{
return m_native_entrypoints + i;
}
}
return nullptr;
}
};
static_assert(sizeof(scrProgram) == 0x80);
}
#pragma pack(pop)

View File

@ -0,0 +1,41 @@
#pragma once
#include <list>
#include "scrProgramTableEntry.hpp"
#pragma pack(push, 1)
namespace rage
{
class scrProgramTable
{
public:
scrProgramTableEntry* m_data; // 0x00
char m_padding[0x10]; // 0x08
std::uint32_t m_size; // 0x18
scrProgram* find_script(joaat_t hash)
{
for (std::uint32_t i = 0; i < m_size; ++i)
{
if (m_data[i].m_hash == hash)
{
return m_data[i].m_program;
}
}
return nullptr;
}
scrProgramTableEntry* begin()
{
return m_data;
}
scrProgramTableEntry* end()
{
return m_data + m_size;
}
};
static_assert(sizeof(scrProgramTable) == 0x1C);
}
#pragma pack(pop)

View File

@ -0,0 +1,17 @@
#pragma once
#include "scrProgram.hpp"
#include "../rage/joaat.hpp"
#pragma pack(push, 1)
namespace rage
{
class scrProgramTableEntry
{
public:
scrProgram* m_program; // 0x00
char m_Pad1[0x04]; // 0x08
joaat_t m_hash; // 0x0C
};
static_assert(sizeof(scrProgramTableEntry) == 0x10);
}
#pragma pack(pop)

31
script/scrThread.hpp Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include "scriptHandler.hpp"
#include "scriptHandlerNetComponent.hpp"
#include "scrThreadContext.hpp"
namespace rage
{
class scrThread
{
public:
virtual ~scrThread() = default; // 0 (0x00)
virtual void reset(std::uint32_t script_hash, void* args, std::uint32_t arg_count) = 0; // 1 (0x08)
virtual eThreadState run() = 0; // 2 (0x10)
virtual eThreadState tick(std::uint32_t ops_to_execute) = 0; // 3 (0x18)
virtual void kill() = 0;
public:
scrThreadContext m_context; // 0x08
void* m_stack; // 0xB0
char m_padding[0x4]; // 0xB8
uint32_t m_arg_size; // 0xBC
uint32_t m_arg_loc; // 0xC0
char m_padding2[0x4]; // 0xC4
const char* m_exit_message; // 0xC8
char m_pad[0x4];
char m_name[0x40]; // 0xD4
scriptHandler* m_handler; // 0x114
scriptHandlerNetComponent* m_net_component; // 0x11C
};
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <cstdint>
#include "../rage/joaat.hpp"
namespace rage
{
enum class eThreadState : std::uint32_t
{
idle,
running,
killed,
unk_3,
unk_4,
};
class scrThreadContext
{
public:
std::uint32_t m_thread_id; // 0x00
joaat_t m_script_hash; // 0x04
eThreadState m_state; // 0x08
std::uint32_t m_instruction_pointer; // 0x0C
std::uint32_t m_frame_pointer; // 0x10
std::uint32_t m_stack_pointer; // 0x14
float m_timer_a; // 0x18
float m_timer_b; // 0x1C
float m_timer_c; // 0x20
char m_padding1[0x2C]; // 0x24
std::uint32_t m_stack_size; // 0x50
char m_padding2[0x54]; // 0x54
};
static_assert(sizeof(scrThreadContext) == 0xA8);
}

81
script/scriptHandler.hpp Normal file
View File

@ -0,0 +1,81 @@
#pragma once
#include <cstdint>
#include "dataList.hpp"
#include "scriptHandlerNetComponent.hpp"
#include "scriptId.hpp"
#include "scriptResource.hpp"
#include "scrThread.hpp"
#pragma pack(push, 1)
namespace rage
{
class scriptHandlerObject;
class scriptHandler
{
public:
class atDScriptObjectNode : public atDNode<scriptHandlerObject*>
{
};
public:
virtual ~scriptHandler() = default; // 0 (0x00)
virtual bool _0x08() = 0; // 1 (0x08)
virtual void _0x10() = 0; // 2 (0x10)
virtual void cleanup_objects() = 0; // 3 (0x18)
virtual scriptId *_0x20() = 0; // 4 (0x20)
virtual scriptId *get_id() = 0; // 5 (0x28)
// Returns whether the script handler belongs to a networked script.
virtual bool is_networked() = 0; // 6 (0x30)
// Initializes the network component for the script handler.
virtual void init_net_component() = 0; // 7 (0x38)
// Deletes the script handler's network component, if it exists.
virtual void reset_net_component() = 0; // 8 (0x40)
// Destroys the script handler.
virtual bool destroy() = 0; // 9 (0x48)
// Adds the object to the script handler's list of objects.
virtual void add_object(scriptHandlerObject*, bool is_network, bool is_network_and_scriptcheck) = 0; // 10 (0x50)
// Something related to reservations.
virtual void _0x58(void*) = 0; // 11 (0x58)
virtual void register_resource(scriptResource*, void*) = 0; // 12 (0x60)
virtual void _0x68() = 0; // 13 (0x68)
virtual void _0x70() = 0; // 14 (0x70)
virtual void _0x78() = 0; // 15 (0x78)
virtual void _0x80() = 0; // 16 (0x80)
virtual void _0x88() = 0; // 17 (0x88)
virtual void _0x90() = 0; // 18 (0x90)
virtual void _0x98() = 0; // 19 (0x98)
public:
void *m_0x08; // 0x08
void *m_0x10; // 0x10
scrThread *m_script_thread; // 0x18
atDList<atDScriptObjectNode> m_objects; // 0x20
scriptResource *m_resource_list_head; // 0x30
scriptResource *m_resource_list_tail; // 0x38
void *m_0x40; // 0x40
scriptHandlerNetComponent *m_net_component; // 0x48
std::uint32_t m_0x50; // 0x50
std::uint32_t m_0x54; // 0x54
std::uint32_t m_0x58; // 0x58
std::uint32_t m_0x60; // 0x5C
};
}
#pragma pack(pop)

View File

@ -0,0 +1,61 @@
#pragma once
#include "../network/netPlayer.hpp"
#include "scriptHandler.hpp"
#include "scrThread.hpp"
#pragma pack(push, 1)
namespace rage
{
class netLoggingInterface;
class scriptHandlerMgr
{
public:
virtual ~scriptHandlerMgr() = default;
// Initializes some scripting-related pools.
virtual bool initialize() = 0; // 1 (0x08)
// Called every tick.
virtual void _0x10() = 0; // 2 (0x10)
// Frees some scripting-related pools.
virtual void shutdown() = 0; // 3 (0x18)
virtual void _0x20() = 0; // 4 (0x20)
virtual void _0x28() = 0; // 5 (0x28)
virtual void _0x30() = 0; // 6 (0x30)
// Generates a rage::scriptId from the thread and copies it over to a global structure.
virtual void _0x38(scrThread*) = 0; // 7 (0x38)
// Allocates and constructs a script handler.
virtual scriptHandler *create_script_handler() = 0; // 8 (0x40)
// Finds the script handler for a given script id.
virtual scriptHandler *get_script_handler(scriptId*) = 0; // 9 (0x48)
// Attaches a script thread.
virtual void attach_thread(scrThread*) = 0; // 10 (0x50)
// Detaches a script thread.
virtual void detach_thread(scrThread*) = 0; // 11 (0x58)
// Called when a player joins.
virtual void on_player_join(netPlayer*) = 0; // 12 (0x60)
// Called when a player leaves.
virtual void on_player_left(netPlayer*) = 0; // 13 (0x68)
virtual std::int32_t _0x70() = 0; // 14 (0x70)
virtual void *_0x78() = 0; // 15 (0x78)
public:
char m_padding1[0x28]; // 0x08
bool m_initialized; // 0x30
bool m_initialized2; // 0x31
char m_padding2[0x0E]; // 0x32
netLoggingInterface *m_logger; // 0x40
};
}
#pragma pack(pop)

View File

@ -0,0 +1,16 @@
#pragma once
#pragma pack(push, 1)
namespace rage
{
class scriptHandler;
class scriptHandlerNetComponent
{
public:
virtual ~scriptHandlerNetComponent() = default;
public:
scriptHandler *m_script_handler; // 0x08
};
}
#pragma pack(pop)

14
script/scriptId.hpp Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "scriptIdBase.hpp"
#pragma pack(push, 1)
namespace rage
{
class scriptId : public scriptIdBase
{
public:
joaat_t m_hash; // 0x08
char m_name[0x20]; // 0x0C
};
}
#pragma pack(pop)

57
script/scriptIdBase.hpp Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include <cstdint>
#include "../rage/joaat.hpp"
#pragma pack(push, 1)
namespace rage
{
class datBitBuffer;
class netLoggingInterface;
class scrThread;
class scriptIdBase
{
public:
virtual ~scriptIdBase() = default; // 0 (0x00)
// Assumes the script thread's identity.
virtual void assume_thread_identity(scrThread*) = 0; // 1 (0x08)
// Returns whether the hash of the script id is valid.
virtual bool is_valid() = 0; // 2 (0x10)
// Gets the hash of the script id.
virtual joaat_t *get_hash(joaat_t *out) = 0; // 3 (0x18)
// Gets an unknown value from the script id.
virtual std::uint32_t *get_hash2(std::uint32_t *out) = 0; // 4 (0x20)
// Gets the name of the script id.
virtual const char *get_name() = 0; // 5 (0x28)
// Serializes the script id from the buffer.
virtual void deserialize(datBitBuffer* buffer) = 0; // 6 (0x30)
// Serializes the script id to the buffer.
virtual void serialize(datBitBuffer* buffer) = 0; // 7 (0x38)
// Calculates some information with the position hash & instance id.
virtual std::uint32_t _0x40() = 0; // 8 (0x40)
// Calls _0x40 and returns it's value added to another value.
virtual std::uint32_t _0x48() = 0; // 9 (0x48)
// Logs some information about the script id.
virtual void log_information(netLoggingInterface* logger) = 0; // 10 (0x50)
// Copies the information of other to this object.
virtual void copy_data(scriptIdBase *other) = 0; // 11 (0x58)
// Returns whether the other script id is equal.
virtual bool operator==(scriptIdBase*) = 0; // 12 (0x60)
virtual bool _0x68(void*) = 0; // 13 (0x68)
};
}
#pragma pack(pop)

10
script/scriptResource.hpp Normal file
View File

@ -0,0 +1,10 @@
#pragma once
namespace rage
{
class scriptResource
{
public:
virtual ~scriptResource() = default;
};
}

17
script/tlsContext.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include "../rage/sysMemAllocator.hpp"
#include "scrThread.hpp"
namespace rage
{
class tlsContext
{
public:
char m_padding1[0xC8]; // 0x00
sysMemAllocator* m_allocator; // 0xC8
char m_padding2[0x758]; // 0xD0
scrThread* m_script_thread; // 0x828
bool m_is_script_thread_active; // 0x830
};
static_assert(sizeof(tlsContext) == 0x838);
}