2019-03-21 20:18:31 +01:00
# pragma once
2022-07-30 18:23:40 +02:00
# include "base/HashTable.hpp"
# include "function_types.hpp"
2019-03-21 20:18:31 +01:00
# include "gta/fwddec.hpp"
2023-04-16 18:28:49 +00:00
# include "gta_pointers.hpp"
2023-04-06 20:01:23 +02:00
# include "memory/batch.hpp"
2022-11-08 03:20:20 +08:00
# include "memory/byte_patch.hpp"
2023-04-06 20:01:23 +02:00
# include "memory/module.hpp"
2023-04-16 18:28:49 +00:00
# include "sc_pointers.hpp"
2023-04-06 20:01:23 +02:00
# include "services/gta_data/cache_file.hpp"
2023-03-01 21:27:15 +00:00
# include "socialclub/ScInfo.hpp"
2023-04-14 18:54:07 +02:00
# include "util/compile_time_helpers.hpp"
2022-12-30 09:45:04 +08:00
2019-03-21 20:18:31 +01:00
namespace big
{
class pointers
{
2023-04-06 20:01:23 +02:00
private :
2023-04-14 18:54:07 +02:00
template < cstxpr_str batch_name , auto batch_hash , size_t offset_of_cache_begin_field , size_t offset_of_cache_end_field , memory : : batch batch >
2023-04-16 18:28:49 +00:00
void write_to_cache_or_read_from_cache ( cache_file & cache_file , const memory : : module & mem_region )
2023-04-14 18:54:07 +02:00
{
static_assert ( batch_hash > 0 ) ;
2023-06-23 14:56:40 +02:00
constexpr size_t field_count = ( offset_of_cache_end_field - offset_of_cache_begin_field ) / sizeof ( void * ) ;
constexpr auto cache_version = batch_hash + field_count ;
cache_file . set_cache_version ( cache_version ) ;
2023-04-14 18:54:07 +02:00
const uintptr_t pointer_to_cacheable_data_start = reinterpret_cast < uintptr_t > ( this ) + offset_of_cache_begin_field ;
2023-04-16 18:28:49 +00:00
if ( ! is_pointers_cache_up_to_date < batch_name > ( cache_file , mem_region ) )
2023-04-14 18:54:07 +02:00
{
run_batch < batch_name > ( batch , mem_region ) ;
const uintptr_t pointer_to_cacheable_data_end = reinterpret_cast < uintptr_t > ( this ) + offset_of_cache_end_field ;
write_pointers_to_cache < batch_name , offset_of_cache_begin_field , offset_of_cache_end_field > ( cache_file , pointer_to_cacheable_data_start , pointer_to_cacheable_data_end , mem_region ) ;
}
else
{
load_pointers_from_cache ( cache_file , pointer_to_cacheable_data_start , mem_region ) ;
}
cache_file . free ( ) ;
}
void load_pointers_from_cache ( const cache_file & cache_file , const uintptr_t pointer_to_cacheable_data_start , const memory : : module & mem_region ) ;
template < cstxpr_str batch_name , size_t offset_of_cache_begin_field , size_t offset_of_cache_end_field >
void write_pointers_to_cache ( cache_file & cache_file , const uintptr_t pointer_to_cacheable_data_start , const uintptr_t pointer_to_cacheable_data_end , const memory : : module & mem_region )
{
constexpr size_t data_size = offset_of_cache_end_field - offset_of_cache_begin_field ;
2023-07-20 22:46:32 +02:00
cache_data cache_data_ptr = std : : make_unique < uint8_t [ ] > ( data_size ) ;
2023-04-14 18:54:07 +02:00
// multiple things here:
// - iterate each cacheable field of the pointers instance
// - substract the base module address so that we only keep the offsets
// - save that to the cache
uintptr_t * cache_data = reinterpret_cast < uintptr_t * > ( cache_data_ptr . get ( ) ) ;
size_t i = 0 ;
for ( uintptr_t field_ptr = pointer_to_cacheable_data_start ; field_ptr ! = pointer_to_cacheable_data_end ; field_ptr + = sizeof ( uintptr_t ) )
{
const uintptr_t field_value = * reinterpret_cast < uintptr_t * > ( field_ptr ) ;
if ( mem_region . contains ( memory : : handle ( field_value ) ) )
{
const uintptr_t offset = field_value - mem_region . begin ( ) . as < uintptr_t > ( ) ;
cache_data [ i ] = offset ;
}
else
{
2023-04-16 18:28:49 +00:00
LOG ( FATAL ) < < " Just tried to save to cache a pointer supposedly within the " < < batch_name . str < < " module range but isn't! Offset from start of pointers instance: " < < ( field_ptr - reinterpret_cast < uintptr_t > ( this ) ) ;
2023-04-14 18:54:07 +02:00
}
i + + ;
}
LOG ( INFO ) < < " Pointers cache: saved " < < ( data_size / sizeof ( uintptr_t ) ) < < " fields to the cache " ;
cache_file . set_data ( std : : move ( cache_data_ptr ) , data_size ) ;
2023-04-16 18:28:49 +00:00
cache_file . set_header_version ( mem_region . size ( ) ) ;
2023-04-14 18:54:07 +02:00
cache_file . write ( ) ;
}
template < cstxpr_str batch_name >
bool is_pointers_cache_up_to_date ( cache_file & cache_file , const memory : : module & mem_region )
{
cache_file . load ( ) ;
2023-04-16 18:28:49 +00:00
if ( cache_file . up_to_date ( mem_region . size ( ) ) )
2023-04-14 18:54:07 +02:00
{
LOG ( INFO ) < < batch_name . str < < " pointers cache is up to date, using it. " ;
return true ;
}
return false ;
}
static constexpr auto get_gta_batch ( ) ;
static constexpr auto get_sc_batch ( ) ;
template < cstxpr_str batch_name , size_t N >
void run_batch ( const memory : : batch < N > & batch , const memory : : module & mem_region )
{
if ( ! memory : : batch_runner : : run ( batch , mem_region ) )
{
const std : : string error_message =
std : : string ( " Failed to find some patterns for " ) + std : : string ( batch_name . str ) ;
throw std : : runtime_error ( error_message ) ;
}
}
2023-04-06 20:01:23 +02:00
2019-03-21 20:18:31 +01:00
public :
explicit pointers ( ) ;
~ pointers ( ) ;
2023-03-01 21:27:15 +00:00
2023-04-06 20:01:23 +02:00
private :
2023-04-14 18:54:07 +02:00
cache_file m_gta_pointers_cache ;
cache_file m_sc_pointers_cache ;
2023-04-06 20:01:23 +02:00
2019-03-21 20:18:31 +01:00
public :
HWND m_hwnd { } ;
2023-04-14 18:54:07 +02:00
gta_pointers m_gta ;
socialclub_pointers m_sc ;
2019-03-21 20:18:31 +01:00
} ;
2022-07-05 16:54:45 -04:00
inline pointers * g_pointers { } ;
2019-03-21 20:18:31 +01:00
}