Análisis profundo de la arquitectura de un motor de juego en C++ con 29,785 símbolos (27,580 líneas), 989 funciones analizadas: complejidad, acoplamiento modular, detección de código muerto y recomendaciones de refactorización.
MasbitsEngine es un motor de juego en C++ con renderer Vulkan que sirve como proyecto central del portfolio. Este análisis estático fue realizado con CodeGraph (análisis AST con Louvain community detection), Daem0n MCP y Engram para evaluar la salud arquitectural del código. 989 funciones analizadas de 29,785 símbolos totales, con corrección por falsos positivos de código condicional #if EDITOR / #if ENGINE.
| Lenguaje | Extensión | Líneas | Porcentaje |
|---|---|---|---|
| C++ | .cpp | 17,553 | 63.7% |
| C++ | .hpp | 9,823 | 35.6% |
| C++ | .h | 204 | 0.7% |
| Total C++ | — | 27,580 | 100% |
| # | Función | Archivo | Cicl. | Cogn. | MI | Líneas |
|---|---|---|---|---|---|---|
| 1 | EditorActions::executeEditorActions | src/Editor/Manager/editorActions.cpp:284 | 58 | 332 | 22.9 | 373 |
| 2 | CVulkanRenderImpl::handleMousePicking | src/RenderCore/Renderer/renderer.cpp:1315 | 54 | 88 | 32.4 | 222 |
| 3 | TilePreviewDialog::renderView | src/Editor/Data/TilePreviewDialog.cpp:1088 | 53 | 163 | 30.6 | 273 |
| 4 | TilesetGenerationDialog::renderView | src/Editor/Data/TilesetGenerationDialog.cpp:1002 | 53 | 163 | 30.6 | 287 |
| 5 | TilesetGenerationDialog::renderGridPreview | src/Editor/Data/TilesetGenerationDialog.cpp:1905 | 49 | 117 | 31.8 | 287 |
El análisis Louvain community detection reveló que los módulos con un alto número de comunidades están fragmentados, lo que indica architectural drift (desviación arquitectural). Cada comunidad representa una agrupación natural de código que debería corresponder a una responsabilidad cohesiva.
| Módulo | Comunidades | Interpretación |
|---|---|---|
RenderCore/BaseRender | 19 | Muy fragmentado — múltiples responsabilidades mezcladas |
Game/Player/AnimStates | 18 | Alta fragmentación — estados de animación dispersos |
Game/Components | 16 | Fragmentado — componentes con responsabilidades cruzadas |
Editor/Data | 15 | Considerable — editor y gestión de datos acoplados |
RenderCore/Renderer | 14 | Significativo — renderer con múltiples sub-responsabilidades |
Alto número de comunidades indica que el código se agrupa naturalmente en muchas comunidades pequeñas en lugar de pocas comunidades grandes y cohesivas. Esto es un síntoma de architectural drift (desviación arquitectural): el código ha evolucionado hacia múltiples responsabilidades dentro de lo que deberían ser módulos con fronteras claras.
Funciones que superan umbrales de complejidad y tienen alto riesgo de bugs. Corregidas las clasificaciones de dead-ffi que no consideraban código dentro de bloques #if condicionales.
| Función | Cognitiva | MI | Llaman | Estado Real |
|---|---|---|---|---|
EditorActions::executeEditorActions | 332 | 22.9 | Sí (appEngineTraits.cpp:63, 100) | #if EDITOR — CodeGraph marcó falso dead-ffi |
loadLevelFromFile | 187 | 13.6 | Sí (editormanager.cpp:113, gamemanager.cpp:50) | Falso dead-ffi — llamada desde ambos modos |
CVulkanRenderImpl::handleMousePicking | 88 | 32.4 | Interna | renderer.cpp — complejidad alta inherente al Vulkan |
CVulkanRenderImpl::buildCommandBuffers | 110 | 22.6 | Interna | 456 líneas, nesting 6 |
TilePreviewDialog::renderView | 163 | 30.6 | Interna | #if EDITOR — falso dead-ffi |
executeEditorActions373 líneas, nesting depth 12, MI 22.9 (crítico). Esta función fue clasificada como dead-ffi por CodeGraph, pero está llamada desde appEngineTraits.cpp:63 y :100 dentro de bloques #if EDITOR. Recomendación: extraer cada caso del switch en su propia función policy-driven, reducir nesting con early returns, y verificar callers dentro de bloques condicionales.
loadLevelFromFileMI 13.6 (crítico). Clasificada como dead-ffi pero llamada desde editormanager.cpp:113 y gamemanager.cpp:50 — existe en ambos modos de compilación. Recomendación: separar parsers por formato en funciones dedicadas, aplicar Strategy pattern para cada tipo de nivel.
Algoritmo de detección de comunidades en grafos que agrupa nodos densamente conectados. Usado para identificar módulos naturales del código y medir la fragmentación. Un alto número de comunidades por módulo indica architectural drift (desviación arquitectural).
Modela las rutas de ejecución dentro de cada función. Permite calcular la complejidad ciclomática (# de rutas independientes) y la complejidad cognitiva (# de decisiones anidadas que el cerebro humano debe rastrear).
Clasificación de funciones como dead-ffi (Foreign Function Interface) — funciones que no tienen llamadores en el grafo de llamadas. Indica código muerto o funciones de API no utilizadas actualmente.
Rastreo de cómo fluyen los datos entre funciones a través de parámetros y valores de retorno. Permite calcular el blast radius (radio de impacto) de cambios y las dependencias transitivas.
| Herramienta | Propósito |
|---|---|
| CodeGraph | Análisis AST con Louvain community detection, CFG analysis, dead-ffi classification, data flow edges y impact analysis |
| Daem0n MCP | AI memory system con persistent context, outcome tracking y semantic search para decisiones arquitecturales previas |
| Engram | Captura de memoria persistente para decisiones técnicas, corrección de errores y patrones establecidos durante el análisis |
| OpenLore | Base de conocimientos con contexto histórico sobre las evoluciones del proyecto y los trade-offs arquitecturales previos |
Puntuación de qué tan difícil es seguir mentalmente el código. Penaliza la anidación (+1 por nivel) y los saltos lógicos (+1 por if/else/for/while). A diferencia de la ciclomática, crece con la profundidad de anidación. Umbral de advertencia: 15.
Número de caminos de ejecución independientes en una función. Se calcula como E - N + 2P (aristas - nodos + 2*componentes conectadas). Umbral de advertencia: 10. No penaliza la anidación directamente.
Puntuación de 0 a 100 que combina la complejidad ciclomática, el número de líneas de código y la ciclomática por LOC. Valores >20 indican código difícil de mantener. 20-25 = crítico, 25-40 = alto riesgo, >40 = aceptable. Umbral de advertencia: 20.
CodeGraph lee archivos fuente directamente sin ejecutar el preprocesador C++ (#if, #ifdef, #endif). Esto causa falsos negativos en la detección de código muerto: funciones llamadas solo dentro de bloques condicionales se clasifican como dead-ffi o dead-leaf aunque existen en el códigobase.
| Paso | Lo que hace CodeGraph | Resultado |
|---|---|---|
| 1. Lectura de fuente | Lee appEngineTraits.cpp directamente | Sin evaluar #if EDITOR |
| 2. AST vacío | Funciones dentro del #if no tienen llamadores | 0 llamadores detectados |
| 3. Clasificación | Sin llamadores → dead-ffi | dead-ffi (falso positivo) |
| 4. Verificación | grep -r "func" --include="*.cpp" encuentra llamadas dentro de #if EDITOR | Código es vivo, no muerto |
| Función | Archivo | Clasificación CodeGraph | Realidad |
|---|---|---|---|
AppEngine::OnEvent | appEngineTraits.cpp:63 | dead-ffi | Callada dentro de #if EDITOR — código vivo |
AppEngine::Run | appEngineTraits.cpp:100 | dead-ffi | Callada dentro de #if EDITOR — código vivo |
dead-ffi, ejecutar grep -r "function_name" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.inl" antes de concluir que el código es no utilizado. Si grep encuentra llamadas dentro de bloques #if, el código es vivo en ese modo de compilación.
Los enfoques fallidos reciben una prioridad 1.5x mayor en búsquedas futuras de Daem0n para evitar repetir métodos que ya demostraron no funcionar con código condicional.
Esta seccion demuestra que el highlighting de Everforest Dark funciona en cualquier pagina del sitio, no solo en blog posts. El siguiente bloque de codigo C++ fue procesado por Shiki via el modulo compartido src/lib/highlighter.ts:
#include <iostream>
int main() {
std::cout << "Hello, Everforest!" << std::endl;
return 0;
}Si ves colores Everforest Dark en este bloque (comentarios en verde claro, strings en amarillo, keywords en rojo), el highlighting esta funcionando correctamente en paginas no-blog.