diff --git a/docs/architecture/editor.md b/docs/architecture/editor.md new file mode 100644 index 0000000..23f700d --- /dev/null +++ b/docs/architecture/editor.md @@ -0,0 +1,369 @@ +# Editor Architecture: Godot Editor Plugin vs. In-Game Editor + +> **Status:** Proposed +> **Owner:** Platform team +> **Related:** World chunk data format & persistence, server authority + client +> prediction, content moderation & age verification, avatar component system +> **Godot version:** 4.6.2 stable + +## 1. Overview + +This document evaluates the two primary ways to build the **world/level +authoring tool** for **agp-game**: + +- **(a) Godot editor plugin** — extend the Godot editor itself with custom + panels, dock widgets, and tools that operate on the project's scenes and + resources. +- **(b) In-game editor** — a fully custom editor built as game UI (Godot + `Control` nodes) that runs inside the running game, editing the game's own + world data. + +The goal is to pick the approach that best fits the platform's constraints: +a **server-authoritative** multiplayer game where the **world is stored as +versioned chunks** (see `world.md`), content is **moderation-flagged** (see +`content_moderation.md`), and the client is a **shipped binary** that players +run (not a dev tool). + +This document is a **decision record**: it lays out the trade-offs, gives a +clear recommendation, and defines the resulting architecture boundaries. + +--- + +## 2. Context & Constraints + +Before comparing the two approaches, we must fix the constraints that drive the +decision. These come from the existing architecture docs. + +### 2.1 The World Is Data, Not Scenes + +`world.md` defines the world as **chunk data** (JSON for authoring, binary for +runtime/network), persisted in SQLite on the server. A chunk is the atomic unit +of load, save, and stream. The **server is the only writer** to the store; +clients submit **deltas** against a `base_revision` and the server validates and +applies them. + +**Implication:** The editor's output is **chunk payloads**, not `.tscn` scene +files. Whatever editor we build must serialize to the chunk contract, not to +Godot scene resources. + +### 2.2 Server-Authoritative & Moderation-Aware + +- The server validates every edit (schema, bounds, moderation) before + persisting (`world.md` §5.4). +- Content carries **content flags** aggregated from referenced assets/scripts + (`content_moderation.md` §3). Mature content is gated behind age verification. +- The client receives a **content manifest** and never loads content not in it. + +**Implication:** An editor that runs on a **player's machine** cannot be the +authority on what gets published. Editing must go through the server's +validation pipeline, and the editor must surface moderation flags. + +### 2.3 The Client Is a Shipped Binary + +The game is a multiplayer product. Players run a **release build**. The Godot +editor is a **development tool** that players do not have. + +**Implication:** If authoring is a first-class *player* feature (user-generated +content), the editor must ship inside the game binary. If authoring is a +*developer/platform* feature, it can live in the editor. + +### 2.4 Two Distinct Audiences + +The evaluation must separate two audiences, because they have opposite needs: + +| Audience | Who | Where they run | What they build | +|----------|-----|----------------|-----------------| +| **Platform/dev** | The team building the game | Godot editor (dev machines) | Base worlds, rooms, templates, test levels | +| **Players (UGC)** | End users | The shipped game | Their own rooms/worlds, published to the server | + +The two approaches map cleanly onto these audiences, and the right answer is +likely **both** — but with a clear primary recommendation. + +--- + +## 3. Approach (a): Godot Editor Plugin + +### 3.1 What It Is + +A Godot editor plugin is a set of scripts (and optionally scenes) that extend +the editor via the `EditorPlugin` API. It can add: + +- **Dock panels** (`add_control_to_dock`) — e.g., a chunk/tile palette panel. +- **Toolbar buttons** (`add_control_to_container`). +- **Inspector plugins** (`EditorInspectorPlugin`) — custom property editors. +- **Import plugins** (`EditorImportPlugin`) — custom asset importers. +- **Scene/Node plugins** (`EditorNode3DGizmoPlugin`) — custom gizmos. +- **Menu entries** (`add_tool_menu_item`). + +Plugins are enabled per-project via `project.godot` (`[editor_plugins]`). + +### 3.2 Pros + +- **Full editor power for free:** You get the scene tree, inspector, viewport + navigation, undo/redo, gizmos, and asset pipeline — all battle-tested. +- **Native Godot editing:** Editing `.tscn` scenes, materials, and nodes is + exactly what the editor is built for. Great for authoring **base content** + (rooms, templates, avatar base bodies). +- **Fast iteration for devs:** The platform team can build and test levels + directly in the tool they already use. +- **Undo/redo, selection, snapping** come from the editor's `EditorUndoRedoManager`. +- **No runtime footprint:** Editor-only code is stripped from export builds + (`@tool` scripts and editor plugins are not shipped to players). + +### 3.3 Cons + +- **Not available to players.** Players don't run the Godot editor. Any + player-facing UGC authoring cannot use this approach. +- **Tied to the editor's UX.** You inherit the editor's look and interaction + model; deep customization is limited by what the editor API exposes. +- **Editor API churn.** `EditorPlugin` APIs change between Godot versions; + plugins are more brittle across upgrades than game code. +- **Scene-centric, not data-centric.** The editor is optimized for scenes and + resources. Our world is **chunk data** (`world.md`). We'd have to build a + translation layer (scene ↔ chunk) and keep it in sync — a real source of + drift. +- **Single-user, local.** The editor edits local files. It does not natively + talk to our server-authoritative chunk store or the moderation pipeline. +- **Headless/CI friction.** Validating plugin behavior in CI requires running + the editor headless, which is heavier than testing game code. + +### 3.4 Fit for Our Constraints + +- **Platform/dev authoring:** Excellent. This is the natural home for building + base worlds, rooms, and templates. +- **Player UGC:** Not applicable. Players cannot run the editor. +- **Server-authoritative chunk store:** Poor fit natively. The editor edits + local scenes; we'd bolt on a chunk export/import and a server sync layer. + +--- + +## 4. Approach (b): In-Game Editor + +### 4.1 What It Is + +A fully custom editor built as **game UI** — Godot `Control` nodes (panels, +buttons, toolbars) that run inside the running game. It edits the game's own +world data model (chunks) and submits edits through the normal server pipeline. + +### 4.2 Pros + +- **Ships to players.** The editor is part of the game binary, so **player UGC + authoring is possible** — the core requirement for a user-generated-content + platform. +- **Data-native.** The editor operates directly on the **chunk model** + (`world.md`), so there is no scene↔chunk translation layer and no drift. +- **Server-authoritative by construction.** Edits go through the same + `request_chunk_edit` RPCs as gameplay, so validation, revisioning, and + moderation apply uniformly. The editor cannot bypass the server. +- **Moderation-aware.** Because edits flow through the server, content flags are + computed and enforced at the boundary (`content_moderation.md` §4). The editor + can surface flags and gate mature content. +- **One codebase, one UX.** The editor uses the same UI toolkit and art style as + the game; no separate editor theme to maintain. +- **Testable in CI.** The editor is ordinary game code; it can be exercised + headlessly and unit-tested like any other system. + +### 4.3 Cons + +- **We build everything.** No free scene tree, inspector, gizmos, or undo/redo. + We must implement selection, snapping, undo/redo, viewport navigation, and + property editing ourselves. +- **Runtime footprint.** Editor UI ships in the binary (though it can be gated + behind a feature flag / separate scene that is only instantiated on demand). +- **More upfront work.** A usable in-game editor is a large feature; it needs + its own architecture (tool modes, gizmos, palette, inspector). +- **Not ideal for deep asset authoring.** Modeling a mesh or authoring a + material is better done in the Godot editor / DCC tools. The in-game editor + should focus on **world composition** (placing tiles and objects), not asset + creation. + +### 4.4 Fit for Our Constraints + +- **Platform/dev authoring:** Workable but not ideal for deep asset work. +- **Player UGC:** The **only** viable approach. Players can only author through + the shipped game. +- **Server-authoritative chunk store:** Excellent fit. The editor is a client + that submits validated deltas. + +--- + +## 5. Comparison Matrix + +| Criterion | (a) Editor plugin | (b) In-game editor | +|-----------|-------------------|--------------------| +| Ships to players | ❌ No | ✅ Yes | +| Player UGC authoring | ❌ Impossible | ✅ Core capability | +| World data model fit | ⚠️ Scene-centric; needs translation layer | ✅ Chunk-native | +| Server-authoritative edits | ⚠️ Bolted on | ✅ Native (same RPCs) | +| Moderation enforcement | ⚠️ Manual | ✅ At the boundary | +| Free editor features (undo, gizmos, inspector) | ✅ Rich | ❌ Build ourselves | +| Runtime footprint | ✅ None (stripped from export) | ⚠️ Ships in binary (gated) | +| Dev iteration speed | ✅ Fast | ⚠️ Slower to build | +| Deep asset authoring (mesh/material) | ✅ Native | ❌ Out of scope | +| CI testability | ⚠️ Heavier (headless editor) | ✅ Ordinary game code | +| Editor API churn risk | ⚠️ Higher | ✅ None (game code) | + +--- + +## 6. Recommendation + +**Primary recommendation: build the in-game editor (b) as the platform's +authoring surface, and use a lightweight Godot editor plugin (a) only as an +internal dev convenience.** + +### 6.1 Rationale + +1. **Player UGC is the deciding factor.** The platform's value proposition is + user-generated content (rooms, worlds, avatars). Players cannot run the Godot + editor, so **only an in-game editor can deliver player authoring**. This is a + hard requirement that the editor-plugin approach cannot meet. + +2. **The world is data, and the in-game editor is data-native.** `world.md` + defines chunks as the atomic unit. An in-game editor edits chunks directly + and submits them through the server pipeline. An editor plugin would force a + scene↔chunk translation layer that is a constant source of drift and bugs. + +3. **Server authority and moderation fall out naturally.** Because in-game + edits use the same `request_chunk_edit` RPCs as gameplay, validation, + revisioning, optimistic concurrency, and content-flag enforcement + (`content_moderation.md`) apply uniformly. The editor cannot bypass the + server — which is exactly what a moderation-aware UGC platform needs. + +4. **The editor-plugin's strengths are not what we need.** Its free features + (scene tree, inspector, gizmos) are for editing Godot scenes and resources. + Our authoring is world composition against a chunk contract, not scene + editing. The plugin's main win — deep asset authoring — is better served by + DCC tools and the Godot editor for the *platform team*, not by a plugin we + must maintain. + +### 6.2 The Role of the Editor Plugin (Dev Convenience Only) + +We still recommend a **small, optional** editor plugin for the **platform team** +to author **base content** (base rooms, templates, avatar base bodies, test +levels) directly in the Godot editor. This is a dev-time convenience, not a +product feature: + +- It can export a scene/resource as a **chunk** (reusing the same encoder as the + in-game editor) so dev-authored content flows into the same pipeline. +- It is **not shipped** to players and is **not** the authoring surface for UGC. +- It should be kept thin to minimize editor-API churn risk. + +### 6.3 Scope Boundary + +To keep the in-game editor tractable, define its scope clearly: + +- **In scope (world composition):** placing tiles, placing static/dynamic + objects, setting transforms, editing object properties, saving/loading chunks, + submitting edits to the server, showing moderation flags. +- **Out of scope (asset creation):** modeling meshes, authoring materials, + rigging avatars. These are done in DCC tools / the Godot editor and imported + as catalog assets (see `avatar.md` §7). The in-game editor **references** + catalog assets by id; it does not create them. + +--- + +## 7. Resulting Architecture + +### 7.1 Shared Editor Core + +Both the in-game editor and the (optional) dev plugin should share a single +**editor core** that operates on the chunk model. This avoids two divergent +implementations. + +``` +EditorCore (shared, data-native) +├── ChunkEditorModel # in-memory chunk being edited (tiles, objects, flags) +├── ChunkEncoder # JSON/binary encode/decode (world.md §3) +├── EditSession # base_revision tracking, delta generation +├── EditSubmitter # request_chunk_edit RPC wrapper + conflict handling +├── UndoRedoStack # command pattern over chunk mutations +├── SelectionManager # selected tiles/objects +├── ToolRegistry # brush, object-place, select, erase, etc. +└── ModerationView # surfaces content flags; gates mature content +``` + +### 7.2 In-Game Editor (Primary) + +``` +InGameEditor (Control-based UI, shipped in binary, gated by feature flag) +├── EditorViewport # custom 2D/3D viewport with camera navigation +├── Toolbar # tool mode switcher +├── PalettePanel # tile/object palette (from catalog) +├── InspectorPanel # property editor for selected object +├── ChunkBrowser # load/save chunks, list rooms +└── EditorCore # shared core (above) +``` + +- Instantiated only when the player enters "build mode" (a separate scene / + feature flag), so the runtime footprint is negligible during normal play. +- Submits edits via `request_chunk_edit`; handles `chunk_edit_result` conflicts + by re-fetching and re-applying (`world.md` §5.4). + +### 7.3 Dev Editor Plugin (Optional, Thin) + +``` +DevChunkPlugin (EditorPlugin, dev-only, not shipped) +├── Dock panel: "Chunk Export" +├── Reads the current scene / selected nodes +├── Maps scene content → chunk model (via EditorCore.ChunkEncoder) +└── Exports a .chunk.json / submits to a dev server +``` + +Kept thin to minimize editor-API churn. Its only job is to let the platform team +author base content in the editor and push it into the same chunk pipeline. + +### 7.4 Data Flow + +``` +[In-game editor] --request_chunk_edit(delta, base_revision)--> [Server] + ^ | validate + | | apply + +--chunk_edit_result(ok/new_revision | conflict)-----------| persist + v + SQLite (world.db) + +[Dev plugin] --export chunk JSON--> [EditorCore.ChunkEncoder] --> [Server] +``` + +Both paths converge on the **same server validation pipeline**, so moderation +and revisioning are uniform regardless of authoring surface. + +--- + +## 8. Risks & Mitigations + +| Risk | Mitigation | +|------|------------| +| In-game editor is a large build | Scope it to world composition (§6.3); reuse EditorCore; ship behind a feature flag | +| Custom viewport/gizmos are hard | Start with a 2D tile editor (matches `CHUNK_SIZE_Z=1` default); add 3D later | +| Undo/redo complexity | Use a command pattern over chunk mutations; test headlessly | +| Editor-plugin API churn | Keep the plugin thin; treat it as dev-only convenience, not a product surface | +| Drift between dev plugin and in-game editor | Both use the same `EditorCore`/`ChunkEncoder` | +| Players bypass moderation | Impossible by construction: edits go through server validation | + +--- + +## 9. Open Questions / Future Work + +- **3D editing:** The default world is flat (`CHUNK_SIZE_Z=1`). A 3D in-game + editor (volumetric chunks) is future work (`world.md` §8). +- **Collaborative editing:** Multiple players editing the same chunk concurrently + — the optimistic-concurrency model already supports it, but the UX (live + cursors, conflict resolution) is unspecified. +- **Template library:** A curated set of room templates players can start from. +- **Publish/review flow:** How a player's authored room enters the moderation + review queue (`content_moderation.md` §6) and becomes publicly joinable. + +--- + +## 10. Summary + +| Concern | Decision | +|---------|----------| +| Primary authoring surface | **In-game editor** (ships to players, enables UGC) | +| Dev authoring convenience | Thin, optional **editor plugin** (not shipped) | +| World data model | Both operate on the **chunk model** via a shared `EditorCore` | +| Server authority | Edits go through `request_chunk_edit`; server validates | +| Moderation | Enforced at the server boundary for both paths | +| In-game editor scope | World composition only; asset creation is out of scope | +| Runtime footprint | Editor gated behind a feature flag / separate scene |