-
Автор темы
- #1
! ВНИМЕНИЕ: Данная тема является переводом гайда с зарубежного форума, ссылка на оригинал - ниже !
Похоже, что перчатки больше не считаются отдельной сущностью в игре (в csgo они были классом EconWearable, но этот класс все еще существует в двоичных файлах cs2). Вместо этого, они кажутся быть просто прикрепленной моделью материала внутри модели просмотра.
-Как же в игре создаются материалы для перчаток?
Прошу не судить строго за названия функций, я старался дать им хоть какой-то смысл. Есть функция, которая, по-видимому, связывает объект C_CSPlayerPawn с экземпляром C_CSGOViewmodel:
Мы можем легко найти эту функцию благодаря очень очевидной строке "default_glove_arm_model".
В самом начале функции, похоже, происходит поиск индексов материалов с помощью функции i под названием "FindMaterialIndexSomething".
Вот прототип функции и используемые типы:
C++:
struct material_record
{
uint_64 ui64_unknown;
uint_32 ui32_unknown;
uint_32 ui32_cached_index;
};
enum material_magic_number : uint_32
{
material_magic_number__gloves = 0xf143b82a,
material_magic_number__unknown1 = 0x1b52829c,
material_magic_number__unknown2 = 0xa6ebe9b9,
material_magic_number__unknown3 = 0x423b2ed4,
material_magic_number__unknown4 = 0xc8d7255e
};
int
find_material_index
(
material_record** p_p_material_info, /* A pointer to the C_CSGOViewModel instance + 0xf28 */
material_magic_number* p_magic, /* A pointer to the magic number, just use the var used for ui32_magic here */
material_magic_number magic, /* Some kind of magic number, for glove materials the game uses 0xf143b82a */
bool* p_b_unused, /* Unused pointer to a bool, havent checked what it does */
);
Итак, идея состоит в том, чтобы заставить игру обновить материал, используемый для перчаток, и протащить в игру нужные нам модели перчаток.
Мы можем сделать это, зайдя в запись материала или что это такое, и заставить его обновиться. Для этого нужно сделать примерно следующее:
C++:
void invalidate_glove_material( C_CSGOViewModel* viewmodel )
{
material_magic_number magic = material_magic_number__gloves;
material_record* mat_records = *reinterpret_cast< material_record** >( reinterpret_cast< uint_8* >( viewmodel ) + 0xf28 );
material_record* record = &mat_records[ find_material_index( &mat_records, &material_magic, material_magic, nullptr ) ];
record->ui32_cached_index = 0xffffffff; /* Invalidates the cached index and forces game to rebuild the material */
}
C++:
E8 ? ? ? ? 4C 63 F0 49 C1 E6 04 4C 03 B7 ? ? ? ? 48 85 FF 74 32 48 8B 47 10 48 85 C0 74 29
/* +1 (absolute) is the find_material_index function*/
/* +15 (32bit offset) is the material records offset*/
Довольно просто, из экземпляра m_EconGloves CEconItemView внутри C_CSPlayerPawn.
Таким образом, если вы делаете полную смену инвентаря, вы можете просто сделать то же самое, что и со скинами, установив itemidhigh+itemidlow+itemdefindex+accountid из вашего C_EconItem.
Вероятно, можно также использовать старый метод установки itemindex в -1 и изменения значений fallback (не проверял).
Кроме того, m_bInitialized экземпляра m_EconGloves CEconItemView должен быть установлен в true, также как и m_bNeedToReApplyGloves внутри C_CSPlayerPawn;
К сожалению, для того чтобы все это заработало, необходимо выполнить еще несколько шагов.
Прежде всего, часть, которая аннулирует индекс материала, должна выполняться как минимум в 2 последовательных кадрах (пример того, как это можно сделать, см. в псевдокоде ниже).
Кроме того, при завершении раунда материал будет обновлен самой игрой и по какой-то причине не будет взят из m_EconGloves.
Поэтому при каждом начале раунда всю процедуру необходимо выполнять заново.
-Full pseudocode
C++:
/* Inside ur framestagenotify hook: */
static uint_8 glove_update_frames = 0;
if( stage != frame_stage__net_update_postdataupdate_end )
continue;
C_CSPlayerPawn* pawn = get_local_player_controller( )->m_hPawn->get< C_CSPlayerPawn* >( );
C_CSGOViewModel* viewmodel = pawn->m_pViewModelServices->m_hViewModel->get< C_CSGOViewModel* >( );
CEconItemView* gloves = pawn->m_EconGloves;
player_team = pawn->m_iTeamNum;
uint_64 wanted_gloves_itemid = config.get( loadout_slot_gloves, player_team ).itemid;
uint_16 wanted_gloves_defidx = config.get( loadout_slot_gloves, player_team ).defidx;
/* Detect if we have to change gloves */
if( gloves->m_iItemID != wanted_gloves_itemid || is_new_round( ) )
{
glove_update_frames = 2;
uint_32 id_low = wanted_gloves_itemid;
uint_32 id_high = wanted_gloves_itemid >> 32;
uint_32 acc_id = steamid;
gloves->m_iItemDefinitionIndex = wanted_gloves_defidx;
gloves->m_iAccountID = acc_id;
gloves->m_iItemID = wanted_gloves_itemid;
gloves->m_iItemIDLow = id_low;
gloves->m_iItemIDHigh = id_high;
}
if( glove_update_frames )
{
invalidate_glove_material( viewmodel );
gloves->m_bInitialized = true;
pawn->m_bNeedToReApplyGloves = true;
glove_update_frames--;}
Пожалуйста, авторизуйтесь для просмотра ссылки.