121 lines
9.0 KiB
Markdown
121 lines
9.0 KiB
Markdown
# Godot Best Practices for OpenWC
|
||
|
||
## Статус
|
||
|
||
Это нормативные правила применения Godot в OpenWC. Они дополняют общую архитектуру и основаны на официальных Godot practices с учётом большого streaming world, native parsers и встроенного Editor tooling.
|
||
|
||
## Nodes только на границах
|
||
|
||
- Domain, packet codecs, validators, coordinate math, build graph и canonical content не должны быть Nodes.
|
||
- Node/Control используются для lifecycle, scene composition, input, rendering/audio presentation и Editor UI.
|
||
- Большой объём однородных данных хранится в typed objects/packed arrays/resources, а не в тысячах служебных Nodes.
|
||
- Scene не ищет глобально dependency по имени; parent composition передаёт contract/reference явно.
|
||
|
||
## Scene organization
|
||
|
||
- Каждая scene имеет одну ответственность и может запускаться в isolation с test doubles.
|
||
- Parent-child означает ownership: удаление parent логично удаляет child. Иначе системы являются siblings/services.
|
||
- Scene наружу публикует небольшой API/signals, а внутренние NodePaths не становятся публичным контрактом.
|
||
- Runtime, render sandbox, preview и capture scenes собираются из общих presenters/services.
|
||
- Generated world preview не сохраняется как authoring source.
|
||
|
||
## Dependency injection и signals
|
||
|
||
- Dependencies передаются composition root, initializer или exported interface reference.
|
||
- Signals используются для notification; commands/intents вызываются через явные методы/bus contracts.
|
||
- Signal connections снимаются симметрично при unload/plugin disable.
|
||
- Не использовать SceneTree groups как скрытый service locator для core architecture.
|
||
|
||
## Autoload policy
|
||
|
||
Autoload разрешён только для действительно process-wide lifecycle:
|
||
|
||
- composition/bootstrap coordinator;
|
||
- глобальная immutable build/version information;
|
||
- crash/diagnostic sink, если ему нужен process lifetime.
|
||
|
||
Gameplay state, network session, renderer world, editor session, caches конкретного проекта и audio emitters не должны становиться неявными глобальными managers. Они создаются/освобождаются владельцем режима.
|
||
|
||
## Resources and data
|
||
|
||
- Resource подходит для immutable/imported descriptors и editor-inspectable configuration.
|
||
- Runtime mutable authoritative state не хранится в shared Resource, который может быть случайно разделён сценами.
|
||
- Resource schema имеет version и migration, если сохраняется пользователем.
|
||
- Original extracted corpus и bulk caches не следует заставлять Godot массово импортировать без необходимости; применять `.gdignore`, custom import staging или native repository.
|
||
- Importer проверяет malformed input и записывает dependency/profile metadata.
|
||
|
||
## Background work
|
||
|
||
- Blocking `load()` не используется в frame-critical streaming path; применяются threaded load/jobs.
|
||
- Worker выполняет file I/O, parsing, decompression, grouping и pure data generation.
|
||
- SceneTree mutation, Node attach и большинство GPU/RID finalization выполняются main thread budget.
|
||
- Один Resource не модифицируется несколькими workers.
|
||
- GDScript container resize/mutation между threads защищается mutex или заменяется message passing.
|
||
- Все worker tasks ожидаются/очищаются; session cancellation не оставляет orphan work.
|
||
|
||
## Rendering performance
|
||
|
||
- Сначала измерять SceneTree/CPU/GPU bottleneck, затем переходить к RenderingServer.
|
||
- Repeated static M2 группировать spatial MultiMesh cells; один MultiMesh на весь мир ухудшает culling.
|
||
- Large transform buffers готовить линейно/в native code и отправлять батчем.
|
||
- Visibility ranges/HLOD, occlusion и automatic mesh LOD использовать совместно по профилю.
|
||
- Unique materials/textures минимизировать; descriptor/resource counts являются budget metric.
|
||
- RenderingServer RIDs имеют явного владельца и освобождаются в deterministic shutdown test.
|
||
- Shader/material profiles разделяют Blizzlike и Enhanced; runtime не компилирует тяжёлые варианты при пересечении ADT boundary.
|
||
|
||
## EditorPlugin lifecycle
|
||
|
||
- Любая регистрация в `_enter_tree()` имеет соответствующее удаление в `_exit_tree()`.
|
||
- Docks, inspectors, importers, gizmos, debugger plugins, signals и jobs снимаются при disable/reload.
|
||
- Editor UI не пишет файлы/SQL напрямую — только создаёт application commands.
|
||
- Mutation интегрирована с EditorUndoRedoManager или общей command history.
|
||
- Preview nodes считаются disposable; stable content IDs не равны instance IDs.
|
||
- Долгая операция имеет progress, cancellation и staging output.
|
||
|
||
## Editor imports and inspectors
|
||
|
||
- Custom import plugin применяется для формата, которому действительно нужен first-class Godot Resource lifecycle.
|
||
- Один extension/type имеет стабильный importer name и version.
|
||
- Platform/profile variants фиксируются явно.
|
||
- Custom inspectors редактируют canonical data через commands и показывают field-level validation.
|
||
- Gizmos не владеют сущностью и создают одну undoable logical operation на drag/stroke.
|
||
|
||
## UI
|
||
|
||
- Control tree не читает network packets и не ищет world nodes.
|
||
- View models immutable на frame/update boundary.
|
||
- Layout использует anchors/containers/theme tokens, а не hardcoded pixel positions вне fidelity backend.
|
||
- FrameXML compatibility layout изолирован от modern Godot-native screens.
|
||
- Input consumption и focus/modal context тестируются сценами.
|
||
|
||
## Profiling and diagnostics
|
||
|
||
- Использовать Godot profiler для script/physics и Visual Profiler для render CPU/GPU.
|
||
- Headless/CLI runs сохраняют JSON metrics; GPU runs фиксируют backend/device/driver/resolution.
|
||
- Performance changes сравниваются cold/warm и p50/p95/p99, а не одним FPS.
|
||
- GPU validation, memory tracking и RenderDoc workflow документируются для shader/backend defects.
|
||
- Custom monitors публикуют streaming queues, cache hits, entities, materials, RIDs и job latency.
|
||
|
||
## Tests
|
||
|
||
- Pure logic тестируется без SceneTree.
|
||
- Scene runner используется только для lifecycle/input/signals/layout/presentation.
|
||
- EditorPlugin имеет enable/disable/reload и undo/save/reload tests.
|
||
- Headless является обязательным CI path; visual tests запускаются отдельно на GPU runner.
|
||
- GdUnit4 рассматривается как кандидат для GDScript/scene tests; native tests остаются отдельным target.
|
||
|
||
## Official references
|
||
|
||
- [Godot Best practices](https://docs.godotengine.org/en/stable/tutorials/best_practices/index.html)
|
||
- [Scene organization](https://docs.godotengine.org/en/stable/tutorials/best_practices/scene_organization.html)
|
||
- [Autoloads versus regular nodes](https://docs.godotengine.org/en/stable/tutorials/best_practices/autoloads_versus_regular_nodes.html)
|
||
- [Background loading](https://docs.godotengine.org/en/stable/tutorials/io/background_loading.html)
|
||
- [Thread-safe APIs](https://docs.godotengine.org/en/stable/tutorials/performance/thread_safe_apis.html)
|
||
- [Optimization using MultiMeshes](https://docs.godotengine.org/en/stable/tutorials/performance/using_multimesh.html)
|
||
- [RenderingServer](https://docs.godotengine.org/en/stable/classes/class_renderingserver.html)
|
||
- [Import plugins](https://docs.godotengine.org/en/stable/tutorials/plugins/editor/import_plugins.html)
|
||
- [Inspector plugins](https://docs.godotengine.org/en/stable/tutorials/plugins/editor/inspector_plugins.html)
|
||
- [3D gizmo plugins](https://docs.godotengine.org/en/stable/tutorials/plugins/editor/3d_gizmos.html)
|
||
- [Command line tutorial](https://docs.godotengine.org/en/stable/tutorials/editor/command_line_tutorial.html)
|
||
- [Debugging tools](https://docs.godotengine.org/en/stable/tutorials/scripting/debug/overview_of_debugging_tools.html)
|