# 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)