main
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
31880f0021 |
feat(examples): gate examples in CI and make repository scripts UTF-8 on every host
`examples/<name>/` was a tested surface in name only. The source-quality job had no examples check at all, and scripts/smoke_examples.sh accepted any process that had not printed one of its error markers: a project that died during startup, exited after a single frame, or crashed without a marker was reported as PASS. Nothing stopped a malformed or unregistered example from reaching dev, which is how 14 examples arrived without READMEs and 20 were never registered in the overview table. Source side - scripts/check_examples.py classifies every directory under examples/ as either runnable (main.nut plus a config.nut that assigns the engine `config` table) or as a reviewed non-runnable sample listed in NON_RUNNABLE_EXAMPLES with a reason. Both kinds must own a README.md and appear in examples/README.md. Stale exemptions and overview links to missing directories fail as well. - `make check/examples` and a new source-quality CI step run the gate. - scripts/tests/test_check_examples.py covers it and pins each failure mode against fixtures. Runtime side - scripts/smoke_examples.sh now enforces liveness, not just marker absence: every runnable example must still be running after MIN_RUN_SECONDS (default 2s; CI passes 2s), and a process that dies inside that window fails whatever its exit code. A clean self-exit after the window passes with an explicit note instead of being silently accepted as a pass. - The Linux CI step sets MIN_RUN_SECONDS=2 and keeps RUN_SECONDS=6, so the job's wall clock is unchanged (13.7 min of its 20 min budget on dev). Windows / GBK - scripts/utf8_stdio.py re-encodes stdout/stderr as UTF-8 and every scripts/*.py program calls it as the first statement of its __main__ block. On a Chinese Windows a redirected stream falls back to the ANSI code page (cp936), and printing a character that code page cannot encode (arrows, superscripts, bullet separators, emoji - all common in this repository) raised UnicodeEncodeError and turned a checker into a traceback. - The mirror image is input: read_text() without encoding= decoded UTF-8 repository text as cp936 and raised UnicodeDecodeError. - scripts/tests/test_utf8_stdio.py enforces both conventions for every script and test module; text file I/O and child-process decoding now pass encoding="utf-8" explicitly. - Unit-test invocations run with `python3 -X utf8` so the runner's own output never follows the host code page. Violations the new gates found on top of dev, fixed here: 14 examples shipped without a README (fluid3d, mesh-impact-lab, mesh-modifier-lab, spline-tube-lab on the earlier dev tip, plus pcg-depth-of-field, pcg-detail-overwrite, pcg-layer-culling, pcg-location-system, pcg-runtime-orchestration, pcg-scene-player-culling, pcg-snow-wind, pcg-thunder-strike, pcg-ui-scaler and pcg-underwater added by #397), 20 were missing from the overview table (those 14 plus archspace-editor, geometry-stroke-lab, interior-mapping, layered-animation, triplanar-decal, terrain-stamping), and scripts/export_meshret_onnx.py had no UTF-8 stdio guard. Verified locally: `python -m ruff check scripts` (All checks passed); scripts/check_test_manifest.py; scripts/check_quality_metadata.py; scripts/check_architecture_contracts.py --base HEAD; scripts/check_nodiscard.py; `make -n check/examples`; scripts/check_examples.py (125 examples: 118 runnable, 7 reviewed non-runnable); and `python -X utf8 -m unittest discover -s scripts/tests -p "test_*.py"` (155 tests, OK). The runtime half of the contract needs a Linux headless build, so it is verified by the CI examples smoke step rather than locally. |
||
|
|
24502babef |
Nest satellite packages under their host modules.
Keep CMake module names and trim switches, but stop flattening editing/editor and runtime bridges as top-level src/modules directories. Parent scans skip nested facets so runtime-3d can drop authoring by directory leaf. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
13a32d8ca7 | ci: teach checks about split metadata sources | ||
|
|
34d1fdb63b |
refactor(modules): clear remaining back-edges and split the largest TUs (#127)
* chore(ci): add clang-format gate, CODEOWNERS and agent collaboration rules * refactor(modules): clear remaining back-edges and split the largest TUs Three known dependency back-edges are gone (module_depgraph.py KNOWN_BACK_EDGES is now empty; --check passes with 0 violations, 0 cycles): - window -> graphics: window queries the new IWindowSurfaceHost capability (common/WindowSurfaceHost.h) instead of holding a Graphics pointer; Window::setGraphics was removed and all call sites updated. - window -> image: Window::setIcon was replaced by setIconRGBA(const uint8_t*, w, h); the window no longer decodes ImageData. - scene -> graphics: pickScreenAt / collectFrustumIdsAt implementations moved to graphics/ScenePicking.cpp (graphics -> scene is a legal downward edge); scene now depends only on spatial. TU splits (pure moves, verified identical method sets and brace balance): - vulkan/Graphics.cpp (5118 lines) -> Graphics.cpp (lifecycle), GraphicsPipeline, Graphics2D, Graphics3D, GraphicsMesh + shared GraphicsInternal.h. - scene/Scene.cpp -> Scene.cpp (script layer / host lifecycle / serialization) + SceneNodes.cpp + shared SceneInternal.h. Verified with a real build (MSVC 19.51, prebuilt third-party): full build green; window.* and Scene.* suites pass, including scene picking/culling and GPU cases. * refactor(graphics): narrow Graphics interfaces and clear public-header leaks Step 4 — interface segregation: - New lean interfaces: IGraphics2D, IGraphics3D, IResourceFactory, IPostFX (pure virtuals, forward-declared types only; graphics/Color.h extracted from Canvas.h so modules that only need the color type stop pulling Canvas.h). - Graphics now implements all four facets; consumers can depend on the narrow interface they use instead of the 129-method god class. - Migrated voxel (VoxelWorld::drawVisible -> IGraphics3D*) and model3d (ModelRenderer::buildRenderable(s) -> IResourceFactory&). - Graphics.h slims from 24 sub-header includes to a handful of small type headers + forward declarations; the destructor moved out-of-line so unique_ptr effect members are destroyed where types are complete. Step 5 — header leaks (module_depgraph.py '*' marks: 14 -> 7): - map/TileLayer.h, particles/ParticleEmitter.h, avatar/AvatarInstance.h, animation/SpineAnim.h, map/TileSystem.h, model3d/ModelData.h, model3d/ModelRenderer.h, audio/Audio.h + Source.h, image/ImageData.h + Image.h, dialogue/Dialogue.h, procgen Palette/OutputSpec/TextureRecipe/ PbrMaterial -> forward declarations, includes moved to .cpp. - voxel/VoxelWorld.h: terrain sampler Pimpl'd (unique_ptr + out-of-line destructor), removing the procgen header dependency. - gpgpu/vulkan backend headers stop pulling graphics/vulkan/Graphics.h. - Remaining '*' marks are deliberate: tiny POD/enum headers (GridConfig, MapObject, BlendMode, Color), an internal backend header (GraphicsInternal.h -> filesystem), and lean interface references. Verified with a full clean build (MSVC) and tests: window/Scene/voxel/ RenderSystem/Quad/shader/TextureSampler/resourceLifetime pass; broad suite only shows the pre-existing PHYSFS-init filesystem-environment failures. * feat(resources): revive ResourceManager as unified IAssetReloader-backed cache * fix(resources): leak ResourceManager singleton to avoid exit-time teardown crashes Cached CPU resources may own third-party handles (FreeType faces, Assimp scenes, image decode handlers) whose libraries are torn down at process exit in an unspecified TU order; destroying cached entries from the singleton destructor can segfault at exit (seen on CI Windows in model3d.materialApi.objMtl). Keep the singleton alive until OS reclaim; explicit unload()/clear() still release entries during the run. * refactor(devtools): consume business modules through capability interfaces DevTools / cmdline no longer include business-module headers, so trimming scene / physics / procgen / particles / audio / ui / graphics no longer requires disabling devtools, and devtools can be switched off with -DEVENGINE_MODULE_DEVTOOLS=OFF. New capability interfaces in common/: - ISceneQuery (scene) - host/node inspection + mutation + transform sync - IRenderCapture (graphics) - render status, PNG capture, camera control, visible-entity snapshot, entity-ID mask, G-buffer PNGs - IPhysicsQuery (physics) - 2D world lifecycle + ray casts - IProcgenQuery (procgen) - recipe listing, map/mesh generation - IParticlesQuery (particles) - emitter status + one-shot emit - IAudioQuery (audio) - volume / stop-all - IEditorHost (ui) - declarative editor host (used by cmdline too) Providers register in their module constructors. DevTools rewires McpServer (render/scene/procgen/physics/particles/audio/host tools), SceneInspect (now delegates to ISceneQuery + IRenderCapture) and RenderVision (uses IRenderCapture::capturePngDataUrl); cmdline/Mcp.cpp uses IEditorHost. manifest: devtools DEPS graphics scene physics procgen particles audio ui image event filesystem -> event; cmdline DEPS filesystem ui -> filesystem. Verified: full build green; devtools.mcp.* tests pass; broad suite shows only the pre-existing PHYSFS-init filesystem-environment failures. * style: apply clang-format to changed lines after dev merge * fix(webgpu): include RenderControl/TextureSampler explicitly after Graphics.h slimming * fix(webgpu): provide newFont/print stubs to satisfy IGraphics2D/IResourceFactory vtables * fix(common): make ProcgenQuery.h self-sufficient (cstdint/utility for GCC) |
||
|
|
ee956e356d |
build: dedupe third-party/system wiring, support all build types, pin deps
Centralize the engine include/link usage in an eve_engine_includes INTERFACE target and the per-platform system library list in cmake/system_libraries.cmake (no more duplicated lists or global include/link dirs). Accept RelWithDebInfo/MinSizeRel, apply the medialoader patch via ExternalProject PATCH_COMMAND instead of mutating the checkout at configure time, pin the third-party aggregate and Dawn to fixed commits, derive the SDK header list from the module manifest, and add deprecation notices for the third-party directory aliases. Also fix message typos and sync test-count docs. |
||
|
|
d80df444aa |
refactor(scene): register link kinds instead of hard-coding them
A scene link keeps an external object in step with the node it hangs off. The kinds were a closed enum with a switch in TransformSystem, so scene had to include graphics, physics and audio to do the casts, and no other module could ever attach to the tree without editing SceneHost.h -- particles, voxel, spritestack, avatar and weather all had to stay outside it. Kinds are registered now (scene/SceneLink.h). The module owning the target type supplies pushWorld / pullWorld / alive, keeps the casts on its own side where the type is complete, and scene never learns what a Renderable3D is. Dispatch is a function-pointer table rather than virtual calls, since link sync runs for every dirty node every frame. The six typed helpers (linkRenderable2D and friends) stay as conveniences and now resolve their kind by name, so they return false rather than crash when the module that registers it was trimmed out. The script API already named kinds with strings, which is exactly the registry key, so it is unchanged. Direction is now the right way round: graphics, physics and audio depend on scene rather than scene on them, and scene drops from L5 to L1. What remains is scene -> graphics from pickScreenAt / collectFrustumIdsAt, which take a Camera3D and read its projection; that is recorded in the back-edge whitelist as the next thing to move. Each provider lives in a SceneLinks.cpp, sharing the basename so the three come out of the build together when scene is disabled. Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com> |
||
|
|
f7aacbc4a9 |
refactor(event): let modules translate their own platform events
The SDL pump did the translation itself, so it had to know about keyboard, joystick, touch, window, graphics, audio and ui: eight upward dependencies from one of the engine's lowest modules, and the source of every remaining dependency cycle. Each module now registers an IPlatformEventSink for the events it owns and the pump only dispatches. Key and text events move to keyboard/sdl, joystick and game-controller events (including the hotplug device table) to joystick/sdl, finger events to touch/sdl, resize and the mobile background/foreground surface watch to window/sdl, the ImGui observer to ui, and Audio::pump to an end-of-pump hook in audio. The pump keeps only quit and window-close, which are about the event loop rather than any one module. Sinks run in priority order -- observer, then surface, then input -- so ImGui still sees events first and the window is resized before anything reads its size. The mobile surface teardown keeps using SDL_AddEventWatch rather than the poll path, since by the time SDL_PollEvent returns the native surface is gone; the watch is now installed by the window module on its first pump. Also removes exceptionIfInRenderPass, whose body has been commented out since it was written and whose only remaining effect was a graphics include. The engine dependency graph now has zero cycles, down from 26, and the back-edge whitelist is down to 2 (window -> graphics, window -> image). Layering is also right way up: event sits at L0 with the input modules above it at L1/L2. Verified: unit tests for event/input/ui/audio/thread pass, and the example smoke suite gives the same 19 pass / 9 fail as the pre-change baseline (those 9 fail on main too, from script API drift in the examples themselves). Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com> |
||
|
|
164e8c1b4c |
refactor(filesystem): dispatch hot reload instead of hard-coding asset kinds
HotReload knew what lived at every watched path: it included graphics to refresh textures, particles to reload emitter configs and map to reload tile layers. That made the engine's lowest-level module depend on three of its highest, and it was the only reason filesystem sat in a dependency cycle. Each module now registers an eve::caps::IAssetReloader for the assets it owns and HotReload only routes paths. Behaviour is unchanged: automatic dispatch still matches by extension, an explicit bind() still targets one kind and ignores the extension, and the texture reloader runs at kTexture priority so the GPU upload happens before emitters and tile layers re-bind to it. The reloadable set now follows the linked module set, so a build without particles simply has no particle reloader rather than a dangling reference. Reload kinds also become extensible: a module or plugin can add one without touching filesystem. Back-edge whitelist 14 -> 11; the dependency graph is now acyclic apart from the event pump. (map.render.tilesContributeDepthY fails when run after the hotreload cases both before and after this change -- pre-existing test-order state, not from here.) Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com> |
||
|
|
08679654e0 |
feat(common): add the capability registry, use it for GPU info and main-thread posts
Introduces eve::cap in common/Capability.h: a name-keyed registry where the
consumer owns the interface, the provider registers an implementation, and
neither includes the other. It generalises what common/RenderTrace.h already
does for the render tracer, and supports both a single provider (provide/query)
and many ordered ones (addListener/forEach), keyed by string so a provider
compiled into a plugin lands in the same slot as the host.
Two upward dependencies go away:
system -> graphics IGpuInfo. The Vulkan physical-device fields move into
graphics/vulkan/GpuInfoProvider.cpp, with a WebGPU
counterpart, so System.cpp loses both the graphics
include and its EVENGINE_WEBGPU branches.
thread -> event IMainThreadPost. postMain and submitPost now enqueue
through the capability. The interface makes explicit
what was previously only a comment in submitPost: the
submitting thread calls prepare() so the worker never
reaches the module registry.
Both now report an error when no provider is linked, rather than lazily
creating a module the build may not contain.
Step S3 of docs/dev/模块编排与裁剪架构.md; back-edge whitelist 16 -> 14.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
|
||
|
|
c4fd641115 |
docs: add module orchestration and trimming architecture analysis
Analyse how the 53 modules currently collaborate and why none of them can be trimmed outside the hardcoded WASM axis, then lay out a target architecture and a six-step route to per-module build options. Adds scripts/module_depgraph.py, which produces the dependency graph, the 7-layer topological ordering and the cycle list the document cites. Its --check mode fails on any back-edge outside the 16 known ones, so it doubles as the CI guardrail for step S1. Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com> |