- Статус
- Оффлайн
- Регистрация
- 13 Фев 2026
- Сообщения
- 347
- Реакции
- 7
Народ, решил слить старый наработок по Apex, который валялся без дела с середины прошлого года. Адекватного скелета под игру давно не видел, одни кривые пасты, так что кому нужно для обучения или базы — забирайте.
Техническая база:
Логика строится на итерации по костям через GetStudioHDR. Скелет собирается через фильтрацию флагов — отсекаем аттачи и прочий мусор, чтобы не ловить лишние линии в рендере.
Что важно знать:
Пока остальные ловят баны на паблик-инжекторах, советую самим разбираться в структурах памяти. Кто уже пробовал допиливать этот алгоритм под актуальные патчи, какие есть затыки с масками флагов?
Техническая база:
Логика строится на итерации по костям через GetStudioHDR. Скелет собирается через фильтрацию флагов — отсекаем аттачи и прочий мусор, чтобы не ловить лишние линии в рендере.
Код:
if (g_config.options.visual.skeleton)
{
auto model_ptr = character->GetModel();
static std::int16_t bone_flags_offset = 0;
static std::int16_t bone_parent_offset = 0;
if (bone_flags_offset == 0)
[[unlikely]]
{
if (auto sig = skCrypt("45 85 6C 9E"))
{
bone_flags_offset = apex.find_pattern(sig).offset(4).deref().cast<std::uint8_t>();
sig.clear();
}
}
if (bone_parent_offset == 0)
[[unlikely]]
{
if (auto sig = skCrypt("49 0F BF 84 5E"))
{
bone_parent_offset = apex.find_pattern(sig).offset(5).deref().cast<std::uint16_t>();
sig.clear();
}
}
auto bone_num = character->GetStudioHDR()->GetBoneCount();
auto matrix = character->GetBoneMatrix();
Vector3D current_bone_screen_pos{};
Vector3D parent_bone_screen_pos{};
for (auto i = 1; i < bone_num; i++)
{
auto bone_flags = *reinterpret_cast<uint32_t*>(model_ptr + 4 * i + bone_flags_offset);
auto parent = *reinterpret_cast<int16_t*>(model_ptr + 2 * i + bone_parent_offset);
// need filter out attachment and some weird [removed]
if ((bone_flags & 0x100) == 0 || (bone_flags & 0x0003FC00) == 0 || (bone_flags & 0x200) == 0)
continue;
if (parent <= 0)
continue;
auto parent_pos = Vector3D(origin.x + matrix[parent][0][3], origin.y + matrix[parent][1][3],
origin.z + matrix[parent][2][3]);
auto current_pos = Vector3D(origin.x + matrix[i][0][3], origin.y + matrix[i][1][3],
origin.z + matrix[i][2][3]);
if (!WorldToScreen(current_pos, current_bone_screen_pos) || !WorldToScreen(
parent_pos, parent_bone_screen_pos))
continue;
g_render.AddDrawListLine({current_bone_screen_pos.x, current_bone_screen_pos.y},
{parent_bone_screen_pos.x, parent_bone_screen_pos.y}, {255, 255, 255, 255});
}
}
Что важно знать:
- Сигнатуры и оффсеты (bone_flags_offset, bone_parent_offset) гарантированно отлетели после обнов. Придется перекатывать под актуальный билд через паттерн-скан.
- Код заточен под структуру матриц из старых сборок. Внимательно чекайте структуру модели.
- Реализация идет через WorldToScreen для каждой пары костей. Рендер в примере через дефолтный ImGui-like DrawList.
Использовались статические переменные для оффсетов с проверкой на 0, что удобно при инициализации. Весь код — это база, которую можно докинуть в свой external проект. Скрывать этот код дальше смысла не вижу, пусть лучше будет здесь, чем гнить в личных папках.
Пока остальные ловят баны на паблик-инжекторах, советую самим разбираться в структурах памяти. Кто уже пробовал допиливать этот алгоритм под актуальные патчи, какие есть затыки с масками флагов?