• Я зарабатываю 100 000 RUB / месяц на этом сайте!

    А знаешь как? Я всего-лишь публикую (создаю темы), а админ мне платит. Трачу деньги на мороженое, робуксы и сервера в Minecraft. А ещё на паль из Китая. 

    Хочешь так же? Пиши и узнавай условия: https://t.me/alex_redact
    Реклама: https://t.me/yougame_official

Гайд External visibility check [FAST] | no mSpotted | Python

Начинающий
Начинающий
Статус
Оффлайн
Регистрация
15 Дек 2024
Сообщения
6
Реакции
6
Хочется поеб*ть себе мозги с wall penetration внешним, без записи в память, так и еще и на питончике. В общем у меня ничего не получилось (пока что).
Но я точно знаю что это возможно и даже кем то уже реализовано. Все данные об объектах на карте в CS2 валве хранят в .vpk, от сюда и начнем.

[Есть два пути]

1) spotted = pm.read_bool(entity_pawn_addr + m_entitySpottedState + m_bSpottedByMask) - Работает криво, медленно
2) Парсинг .vpk файлов карт - Затратно, быстро, а работоспособность зависит от рук (в моем случае их отсутствия)

[.vpk -> .vphys]

Сначала нам нужен
Пожалуйста, авторизуйтесь для просмотра ссылки.
, потребуется чтобы получить данные из .vpk (потом можно будет автоматизировать)
Снимок экрана 2025-04-06 170640.png
Снимок экрана 2025-04-06 170720.png
Снимок экрана 2025-04-06 170837.png
В итоге получаем файл world_physics.vphys для карты de_mirage. Его вес около 25мб, из которых 23мб мусор, нужные нам треугольнички и вершины можно получить спарсив файл.

[.vphys -> .opt]

Можете использовать парсер
Пожалуйста, авторизуйтесь для просмотра ссылки.
, компилируйте Release X64 ISO C++ 20. Указываете директорию в которой лежат ваши .vphys файлы, дальше парсер должен отработать примерно так:

Код:
Expand Collapse Copy
C:\VPhysToOpt\x64\Release>VPhysToOpt C:\PythonCODE\ProjectX
Processing C:\PythonCODE\ProjectX\world_physics.vphys -> C:\PythonCODE\ProjectX\world_physics.opt
Successfully saved: C:\PythonCODE\ProjectX\world_physics.opt

Если кому то интересно, то .opt[imized] - бинарный файл, содержащий только объединённые данные о треугольниках и вершинах, находящихся в .vphys файле.

[VisCheckCS2]

Можете использовать исходник
Пожалуйста, авторизуйтесь для просмотра ссылки.
, но так как я хочу все это использовать в python, то сначала делаю pip install pybind11, далее компилирую
Пожалуйста, авторизуйтесь для просмотра ссылки.
Release X64 ISO C++ 20 указав в Configuration Properties → C/C++ → General → Additional Include Directories каталоги C:\Users\ИМЯЮЗЕРА\AppData\Local\Programs\Python\PythonВЕРСИЯ\include; C:\Users\ИМЯЮЗЕРА\AppData\Local\Programs\Python\PythonВЕРСИЯ\Lib\site-packages\pybind11\include. В Configuration Properties → Linker → General → Additional Library Directories указываю C:\Users\ИМЯЮЗЕРА\AppData\Local\Programs\Python\PythonВЕРСИЯ\libs.

По итогу получите модуль vischeck.pyd — это питоновский бинарник для проверки видимости между точками в 3D-пространстве. Работает так: когда ты вызываешь is_visible(point1, point2), он строит луч из point1 в point2 и рекурсивно проверяет пересечения этого луча с AABB боксами в BVH. Если луч попадает в бокс — проверяет треугольники внутри. Если пересечение найдено и оно ближе чем point2 — точки не видимы. Для проверки пересечений используется алгоритм Мёллера-Трумбора.

[Пример использования]
Python:
Expand Collapse Copy
import vischeck
import random
import time

start_loader = time.time()
checker = vischeck.VisCheck("C:\VPhysToOpt\world_physics.opt") # ваша карта
end_loader = time.time()
print('loader map time:', end_loader - start_loader)

for i in range(1000):
    me = (random.randint(-3000, 3000), random.randint(-3000, 3000), random.randint(-3000, 3000))
    enemy = (random.randint(-3000, 3000), random.randint(-3000, 3000), random.randint(-3000, 3000))
    start_time = time.time()
    r = checker.is_visible(me, enemy)
    end_time = time.time()
    print('time to 1 ray: ', end_time - start_time, 'result:', r) # время обработки (чаще всего 0.0) и результат True/False
В реальном коде чита получаем коорды хеда противника и меня, ну мой говнокод вышел таким:
Python:
Expand Collapse Copy
import vischeck

checker = vischeck.VisCheck("mirage.opt")

def vischeck(pm, entity_pawn_addr, local_player_pawn_addr):
    global checker
    game_scene = pm.read_longlong(entity_pawn_addr + m_pGameSceneNode)
    bone_matrix = pm.read_longlong(game_scene + m_modelState + 0x80)
    data = pm.read_bytes(bone_matrix + 6 * 0x20, 3 * 4)
    local_game_scene = pm.read_longlong(local_player_pawn_addr + m_pGameSceneNode)
    local_bone_matrix = pm.read_longlong(local_game_scene + m_modelState + 0x80)
    local_data = pm.read_bytes(local_bone_matrix + 6 * 0x20, 3 * 4)
    me = struct.unpack('fff', local_data)
    enemy = struct.unpack('fff', data)
    
    return checker.is_visible(me, enemy)

*fov и небо были заменены через сторонние программы

[Зачем оно надо?]
  • База для ИИ на python
  • База для ботов
  • Пример для трассировки пуль
  • Пример для проверки позиций
И конечно vischeck для читов, сам по себе проект
Пожалуйста, авторизуйтесь для просмотра ссылки.
вызвать VAC не может никак! Тут нету взлома игры или чтения с записью памяти, мы просто читаем файлик .opt и все. Бан же дадут если проект использовать в чите, где есть оверлей, чтение запись памяти и тд. (надо постараться забаниться еще с VAC`ом то :/ )

[P.s.]
Я знаю что таких проектов уже куча, взять тот же
Пожалуйста, авторизуйтесь для просмотра ссылки.
.
У меня он не завелся почему то :(

На видео мой чит на python, написанный только на чтение игры из kernal ядра.

Код полное говнище, вообще весь, загрузка карты inferno весом в 690мб займет примерно 68 секунд КАРЛЛ

Инфа от сюда:

Мой проект:
Пожалуйста, авторизуйтесь для просмотра ссылки.
, готовой .pyd либы и .exe парсера НЕ БУДЕТ, потому что меня обвинят в том что я этакий плохой НН вирусы втираю. Не малые - сами скомпилируете.
 
[P.s.s]
Забыл написать, у многих новых карт и у всех карт из мастерской в
Пожалуйста, авторизуйтесь для просмотра ссылки.
будет отсутствовать файл .vphys_c, но точно должен быть файл .vmdl_c, в нем храниться идентичная информация что и в .vphys_c. Просто заходите в графу phys в .vmdl_c и копируете в txt файл, позже переименовывая в .vphys. У меня все получилось, парсер отработал как надо. Вообще валве формат .vphys считают устаревшим и более не используют
 
Это под каждую карту отдельно нужно делать?)
 
there's some issues with your version that'll bite you on larger maps (eg inferno - 100MB):


Your approach copies the entire triangle vector multiple times during recursion - for a mesh with like 500k+ triangles (inferno 2.8 million) this creates massive memory overhead and will probabaly crash. The index-based approach i used avoids constantly copying triangle data around.


some map files can have millions of triangles. Your version will just choke on anything substantial
Also skipping meshes over 1M triangles prevents crashes on huge maps that are pretty common in servers. Your simplified version tries to process everything and will likely run out of memory.


The LEAF_THRESHOLD thing is debatable - 1 can actually be better for ray tracing depending on your traversal implementation, i just dont mind sacrificing load times to get more FPS

correction:
Expand Collapse Copy
const size_t LEAF_THRESHOLD = 1;

VisCheck::VisCheck(const std::string& optimizedGeometryFile) {
    std::cout << "VisCheck: Starting to load file: " << optimizedGeometryFile << std::endl;
    if (!geometry.LoadFromFile(optimizedGeometryFile)) {
        std::cout << "Failed to load optimized file: " << optimizedGeometryFile << std::endl;
        return;
    }
    std::cout << "VisCheck: File loaded successfully, found " << geometry.meshes.size() << " meshes" << std::endl;

    const size_t MAX_TRIANGLES_PER_CHUNK = 100000; // 100k triangles per BVH
    const size_t MAX_TRIANGLES_TO_PROCESS = 1000000; // skip meshes larger than 1M triangles lol

    for (size_t i = 0; i < geometry.meshes.size(); ++i) {
        const auto& mesh = geometry.meshes[i];
        std::cout << "VisCheck: Processing mesh " << i << " with " << mesh.size() << " triangles" << std::endl;

        // Skip extremely large meshes
        if (mesh.size() > MAX_TRIANGLES_TO_PROCESS) {
            std::cout << "VisCheck: Skipping mesh " << i << " - too large (" << mesh.size() << " triangles)" << std::endl;
            // Create empty BVH node for consistency
            bvhNodes.push_back(std::make_unique<BVHNode>());
            continue;
        }

        if (mesh.size() <= MAX_TRIANGLES_PER_CHUNK) {
            auto start = std::chrono::high_resolution_clock::now();
            bvhNodes.push_back(BuildBVH(mesh));
            auto end = std::chrono::high_resolution_clock::now();
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
            std::cout << "VisCheck: BVH completed in " << duration.count() << "ms" << std::endl;
        }
        else {
            size_t numChunks = (mesh.size() + MAX_TRIANGLES_PER_CHUNK - 1) / MAX_TRIANGLES_PER_CHUNK;
            std::cout << "VisCheck: Large mesh - splitting into " << numChunks << " chunks" << std::endl;
            for (size_t chunkIdx = 0; chunkIdx < numChunks; ++chunkIdx) {
                size_t start_idx = chunkIdx * MAX_TRIANGLES_PER_CHUNK;
                size_t end_idx = std::min(start_idx + MAX_TRIANGLES_PER_CHUNK, mesh.size());
                std::vector<TriangleCombined> chunk(mesh.begin() + start_idx, mesh.begin() + end_idx);
                std::cout << "VisCheck: Processing chunk " << (chunkIdx + 1) << "/" << numChunks
                    << " (" << chunk.size() << " triangles)" << std::endl;
                auto start = std::chrono::high_resolution_clock::now();
                bvhNodes.push_back(BuildBVH(chunk));
                auto end = std::chrono::high_resolution_clock::now();
                auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
                std::cout << "VisCheck: Chunk " << (chunkIdx + 1) << " completed in " << duration.count() << "ms" << std::endl;
            }
        }
    }
    std::cout << "VisCheck: Constructor completed with " << bvhNodes.size() << " BVH trees" << std::endl;
}


std::unique_ptr<BVHNode> VisCheck::BuildBVH(const std::vector<TriangleCombined>& tris) {
    return BuildBVHIterative(tris);
}


std::unique_ptr<BVHNode> VisCheck::BuildBVHIterative(const std::vector<TriangleCombined>& triangles) {
    if (triangles.empty()) {
        return std::make_unique<BVHNode>();
    }
    std::vector<size_t> indices(triangles.size());
    std::iota(indices.begin(), indices.end(), 0);

    return BuildBVHFromIndices(triangles, indices);
}

std::unique_ptr<BVHNode> VisCheck::BuildBVHFromIndices(
    const std::vector<TriangleCombined>& triangles,
    const std::vector<size_t>& indices) {

    auto node = std::make_unique<BVHNode>();

    if (indices.empty()) return node;

    AABB bounds = triangles[indices[0]].ComputeAABB();
    for (size_t i = 1; i < indices.size(); ++i) {
        AABB triAABB = triangles[indices[i]].ComputeAABB();
        bounds.min.x = std::min(bounds.min.x, triAABB.min.x);
        bounds.min.y = std::min(bounds.min.y, triAABB.min.y);
        bounds.min.z = std::min(bounds.min.z, triAABB.min.z);
        bounds.max.x = std::max(bounds.max.x, triAABB.max.x);
        bounds.max.y = std::max(bounds.max.y, triAABB.max.y);
        bounds.max.z = std::max(bounds.max.z, triAABB.max.z);
    }
    node->bounds = bounds;

    if (indices.size() <= LEAF_THRESHOLD) {
        node->triangles.reserve(indices.size());
        for (size_t idx : indices) {
            node->triangles.push_back(triangles[idx]);
        }
        return node;
    }

    Vector3 diff = bounds.max - bounds.min;
    int axis = (diff.x > diff.y && diff.x > diff.z) ? 0 : ((diff.y > diff.z) ? 1 : 2);

    std::vector<std::pair<float, size_t>> centerIndex;
    centerIndex.reserve(indices.size());

    for (size_t idx : indices) {
        AABB aabb = triangles[idx].ComputeAABB();
        float center;
        if (axis == 0) {
            center = (aabb.min.x + aabb.max.x) * 0.5f;
        }
        else if (axis == 1) {
            center = (aabb.min.y + aabb.max.y) * 0.5f;
        }
        else {
            center = (aabb.min.z + aabb.max.z) * 0.5f;
        }
        centerIndex.emplace_back(center, idx);
    }

    std::sort(centerIndex.begin(), centerIndex.end());

    size_t mid = centerIndex.size() / 2;
    std::vector<size_t> leftIndices, rightIndices;
    leftIndices.reserve(mid);
    rightIndices.reserve(centerIndex.size() - mid);

    for (size_t i = 0; i < mid; ++i) {
        leftIndices.push_back(centerIndex[i].second);
    }
    for (size_t i = mid; i < centerIndex.size(); ++i) {
        rightIndices.push_back(centerIndex[i].second);
    }

    node->left = BuildBVHFromIndices(triangles, leftIndices);
    node->right = BuildBVHFromIndices(triangles, rightIndices);

    return node;
}
 
+реп, работает очень плавно
 
Назад
Сверху Снизу