Checkpoint 2: integrate native Editor, MCP, gameplay builds and standalone export

This commit is contained in:
Emil
2026-09-18 03:40:15 +03:00
parent 5c6b24d34d
commit 999686a896
125 changed files with 16086 additions and 1714 deletions
+28 -29
View File
@@ -1,41 +1,40 @@
# C++ gameplay
In the first version of Faset, a "script" is C++ gameplay code compiled into your game.
It is not an interpreted text file. The gameplay library is statically linked into
a separate Player executable.
In Faset, a gameplay script is **C++ compiled into the Player**. You write ordinary functions and register the callbacks an object needs. There is no C++ interpreter or live replacement of compiled classes. Stop Play, rebuild, export the schema, and start a new Player session.
The intended iteration cycle is:
Lua is planned for a later stage. The APIs and tutorials in this section describe the C++ implementation available now.
1. Stop Play.
2. Edit your C++ behavior or system.
3. Build the changed code and export its property schema.
4. Start a new Player session.
## Start here
The Editor reads a schema generated by a separate SchemaExporter. It does not load
your gameplay library into its own process. A gameplay crash therefore does not
automatically crash the Editor. Editor native extensions have a different lifecycle
and run inside the Editor process.
1. Read [Your first behavior](first-behavior.md) and run the moving-object example.
2. Learn [when callbacks run](lifecycle.md) before mixing frame updates and physics.
3. Build a [physics character](physics.md) that can move and jump from the floor.
4. Try [following, spawning, and timed destruction](examples.md).
5. Keep the [runtime API reference](api.md) nearby while writing code.
!!! note "API examples are added with implementation"
This page describes the accepted execution model. Exact function signatures and
complete examples will be documented alongside compiling runtime examples, rather
than presenting proposed APIs as available functions.
The complete tutorial modules are compiled and executed by CTest. The code blocks include those source files directly, so the manual does not maintain separate, untested copies.
## Behaviors and systems
## What belongs to your module
A behavior gives an individual object lifecycle callbacks. A system operates on a
set of objects with matching components. Both use the same runtime state; the visual
scene and Inspector are the authoring view of that state.
A gameplay directory contains `Gameplay.hpp` and `Gameplay.cpp`. It provides two functions in `faset::gameplay`:
Persistent scene IDs and runtime handles are different. A scene ID survives saving
and reopening. A runtime handle belongs to a particular world/session and can become
invalid after an object is removed. Do not store raw component pointers across
structural changes or treat a runtime handle as a save-file ID.
- `registerGameplay(runtime::Runtime&)` registers executable behavior callbacks.
- `schema()` returns a JSON array of component descriptions: stable type and field IDs, versions, defaults, constraints, and Inspector hints.
## Physics ownership
The Player calls registration before loading a scene. The separate SchemaExporter calls `schema()` without creating a game world or running gameplay callbacks. The Editor reads the resulting declaration; it does not load the gameplay binary into the Editor process.
Physics owns the position of a dynamic rigid body. Move it with the supported physics
commands instead of writing its presentation transform. A camera or other visual-only
object can follow the interpolated result without modifying the simulation.
A scene object receives a behavior by containing a component whose `type` matches the string passed to `registerBehavior`. Registering a behavior does not attach it to every object. A component can contain data without having any callbacks.
Continue with [Frame and physics updates](lifecycle.md).
## Data, poses, and state
`fields(self, type)` returns a **copy of component configuration**. Editing that copy changes neither the saved scene nor the runtime configuration. `transform(self)` returns a copy of the current simulation pose; pass the changed copy to `setTransform` for a non-physical object. A rigid body uses `setVelocity`, `applyImpulse`, or an explicit `teleport` instead.
Ordinary C++ state can be captured by callbacks. The spawning tutorial shows state indexed by the full runtime handle and cleaned up in `onDestroy`. Do not capture a reference to a local variable that will disappear after `registerGameplay` returns. Use owned state, or ensure the referenced object outlives the runtime.
Scene IDs are saved strings. `EntityHandle` is a temporary reference containing a session, slot, and generation. It must not be written into a save file. Resolve a scene ID with `find`, check `valid`, and expect old handles to stop working after removal or a new Play session.
## Current boundaries
These examples use per-object callbacks and the implemented typed pose/physics API. They do not provide a universal binding for arbitrary C++ classes, a public EnTT registry, or a general parallel-system scheduler. The runtime is sequential and has one owning thread.
MCP belongs to the Editor's authoring, import, build, and process-control services. It does not invoke runtime methods or inspect the live game world. A C++ gameplay change requires the same rebuild whether a person or an agent edited the source.