-
Автор темы
- #1
И так, так как у нас отличаются id костей у разных героев, и что бы не описывать для каждого героя нужный id костей, или не писать функцию которая будет для каждой кости проходиться всем ищя именно с нужным именем, воспользуемся игровыми функциями GetBonePos и LookUpBone:
(p.s.сигнатуры взяты с другого форума no ad)
GetBonePos - возвращает позицию по id.
LookUpBone - возвращает id по имени.
Стоит обратить внимание на то, что обе функции принимают указатель на пешку игрока, но при этом стоит учитывать что в случаях по мимо обычных ентити(самих игроков), мы должны передавать указатель на 'контроллер', тк у них контроллер и пешка условно 'равны' (речь про соул орбы, крипов, босов и т.д.).
Т.е. если для обычного игрока мы получаем контроллер, из него пешку, и дальше работаем с ним.
То для остальных ентити, то как мы получаем контроллер, можно сразу кастовать на пешку:
Теперь нам достаточно просто пробежаться по всем нужным именам циклом:
Для примера буду просто отрисовывать круги на месте костей:
Список основных костей(их хватит для есп и аима(для мультипоинтов возможно вам понадобиться больше костей(и их имен) в зависимости от реализации мультипоинтов):
Результат:
(p.s.сигнатуры взяты с другого форума no ad)
bone func:
Vector3 GetBonePosition(void* entity, int bone) {
using fnGetBonePosition = void(__thiscall*)(void*, int, Vector3&, Vector3&);
static auto GetBonePositionFunc = reinterpret_cast<fnGetBonePosition>(PatternScan("client.dll", "48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC ?? 4D 8B F1 49 8B E8 8B F2"));
Vector3 pos, rot;
GetBonePositionFunc(entity, bone, pos, rot);
return pos;
}
int LookupBone(void* entity, const char* bone) {
using fnLookupBone = int(__thiscall*)(void*, const char*);
static auto LookupBoneFunc = reinterpret_cast<fnLookupBone>(PatternScan("client.dll", "40 53 48 83 EC ?? 48 8B 89 ?? ?? ?? ?? 48 8B DA 48 8B 01 FF 50 ?? 48 8B C8"));
return LookupBoneFunc(entity, bone);
}
LookUpBone - возвращает id по имени.
Стоит обратить внимание на то, что обе функции принимают указатель на пешку игрока, но при этом стоит учитывать что в случаях по мимо обычных ентити(самих игроков), мы должны передавать указатель на 'контроллер', тк у них контроллер и пешка условно 'равны' (речь про соул орбы, крипов, босов и т.д.).
Т.е. если для обычного игрока мы получаем контроллер, из него пешку, и дальше работаем с ним.
То для остальных ентити, то как мы получаем контроллер, можно сразу кастовать на пешку:
pseudo:
// для обычного игрока
CPlayerController* Controller = dwEntityList->Get<CPlayerController>(i);
CPlayerPawn* Pawn = dwEntityList->Get<CPlayerPawn>(Controller->GetHandlePawn());
//для остальных ентити
auto trooper = dwEntityList->Get<CPlayerPawn>(i);
Теперь нам достаточно просто пробежаться по всем нужным именам циклом:
Для примера буду просто отрисовывать круги на месте костей:
C++:
for (int i = 0; i < sizeof(bones) / sizeof(bones[0]); i++) {
int boneIndex = LookupBone(trooper, bones[i]);
Vector3 bonePos = GetBonePosition(trooper, boneIndex);
Vector3 screenBone;
if (world_to_screen(vm.vm, bonePos, bone2d)) {
drawList->AddCircle(screenBone, 5, IM_COL32(255, 255, 255, 255));
}
}
C++:
const char* bones[] = {
"head", // Голова
"neck_0", // Шея
"spine_0", // Верхняя часть спины
"spine_1", // Нижняя часть спины
"clavicle_L", // Левое плечо
"arm_upper_L", // Верхняя часть левой руки
"hand_L", // Левая рука
"pelvis", // Таз
"clavicle_R", // Правое плечо
"arm_upper_R", // Верхняя часть правой руки
"hand_R", // Правая рука
"leg_upper_L", // Левое бедро
"leg_lower_L", // Левая голень (колено)
"ankle_L", // Левая ступня
"leg_upper_R", // Правое бедро
"leg_lower_R", // Правая голень (колено)
"ankle_R", // Правая ступня
"arm_lower_L", //плечо
"arm_lower_R" //плечо
};
Пожалуйста, авторизуйтесь для просмотра ссылки.