o2 dev
108 subscribers
49 photos
4 videos
25 files
54 links
About o2 engine development
Download Telegram
В общем, эта классная идея не выгорела даже на этапе компиляции. Проблема в С++, в концепции инклюдов и forward-declaration'ах. Ему становится плохо от таких специализаций...

Дело в том, что если в .cpp не будет подключен .h, содержащий вашу частичную специализацию, то компилятор о ней и не узнает, и просто возьмет не специализированный шаблонный класс, и сделает его инстанс. То есть Ref<Actor> заработает как обычный указатель, и не будет уметь сериализоваться/делать нужные штуки. Проблем добавляет цикличность зависимостей - class Actor уже хочет знать о существовании специализации Ref<Actor>, и приходится хитро форвардить. А так как в самом class Actor тоже есть шаблонные методы, например Ref<T> FindActorByType<T>(), то просто зафорвардить не получится, т.к. реализация функции в том же .h где и форвард, и компилятор ругается на отсутствие реализации Ref<T>, который определен только forward'ом. Это решаемо, но через уродливые #include "" посреди .h, что выглядит как минимум странно

Но еще больше проблем вызывает то, что пользователь может попросту забыть включить хидер со специализацией и получит неправильное поведение. То есть довольно легко отстрелить колено так, что не поймешь откуда прилетело.

Еще сильнее колено отстреливается когда в .h нет нужной специализации, а в .cpp она появляется. Здесь происходит откровенный пиздец, т.к. компилятор думает что класс определен с Ref<> одного размера (8 байт на указатель), а реализацию функций с другим` Ref<>` (8 байт на указатель + 8 байт на вспомогательную инфу). В рантайме это выглядит как запись вне стека/участка памяти и шваркается рандомно. Слава господи address sanitizer сразу подсвечивает такие проблемы. Хотя разобраться в таком креше - это капец, абсолютно не понимаешь почему у тебя программа пытается писать за пределами объекта в конструкторе.

Об этом писал в своей статье в предыдущем посте, что такой проблемы в принципе бы не существовало, будь у С++ другая стратегия компиляции, без инклюдов и форвардов.
и здесь я сразу решил с ноги зайти и просто написать что за тулзу я хочу. Да да, одним промтом, вот прям из коробки.
За основу я взял демо-проект imgui со своим прикрученным профайлером

Вот первый промт:
я хочу сделать графическую утилиту, которая сканирует исходники С++ в нескольких папках, строит зависимости, и отображает с помощью imgui в графическом виде эти зависимости. Графически эти зависимости кластеризуют связанные сущности (исходники), с помощью физических законов. Сущности представлены в виде цветных кружков, зависимости (или связи) в виде линий.

Зависимости строятся на 2х уровнях:
- иерархия папок и подпапок: для каждой директории создается сущность директории, дочерняя директория зависит от родительской. Внутри директории есть список сущностей - файлов в ней
- зависимости между исходниками С++ через #include: из каждого исходника парсится список инклюдов, ищутся файлы-исходники по путям и между ними создается связь

Работа физики:
- для этого сущности расположены в 2д мире, у каждого есть позиция
- между ними есть зависимости- связи, которые задают некое расстояние между сущностями
- сущности стараются оттолкнуться от билзлижащих сущностей
- используется интеграция верле и разрешение связей как в научной работе якобсена из hitman codename 47
- при зажимании левой кнопки мыши умеет захватывать сущность чтобы ее перемещать вслед за курсором

Графика:
- используется imgui Для отображения. В текущем исходнике Main.cpp создается дополнительное окно, в котором отображается вся графика: сущности и связи
- сущности - это разноцветные круги
- связи - это линнии между ними
- существует камера, которой можно управлять: скролл (перемещение) с зажатой правой кнопкой мыши, зум с помощью колесика
- наведение курсора на сущность включает ее подсветку: отображается имя исходника, а так же связь с родителем и детьми
- для профилирования используется nano profiler: работа физики и графики

что нужно сделать:
- завести json конфиг с параметрами: исходные директории для сканирования, настройки графики и физики. Работает как отдельный класс
- сделать класс парсера исходников с многопоточностью: берет исходные директории из json конфига и рекурсивно сканирует их в поисках C++ исходников .h/.cpp, парсит #include, связывает сущности, создает сущности для всех директорий
- физический движок, оптимизированный для вычисления 10000 сущностей и 30000 связей. Инициализируется из парсера исходников, сохраняя ссылки на исходные сущности. ПРоводит симуляцию мира и физики: интегрирует позиции, разрешает связи, расталкивает близлижащие сущности
- графическое отображение. Содержит камеру, обрабатывает инпут пользователя, отображает сущности и связи
- главный класс утилиты: читает конфиг, парсит исходники, инициализирует физику и графику, запускает игровой цикл апдейта фрейма - обонвление физики, обработка инпута и отрисовка

Разделяй вышеописанное на классы в разных файлах, рядом с Main.cpp. Используй для всего стандартную библиотеку stl и imgui. Не используй ничего кастомного, никаких скриптов, только С++