more refactor
This commit is contained in:
+5
-5
@@ -107,9 +107,9 @@ Owns the board behind an `Rc<RefCell<Board>>`, alongside the message `log` and a
|
||||
|
||||
Two optional lifecycle hooks per object: `init()` (zero-arg, run once) and `tick(dt)` (elapsed seconds as `f64`, run per frame), driven by `run_init()` / `run_tick(dt)`. Runtime errors become `Error` commands, not fatal.
|
||||
|
||||
**Reads vs writes.** Scripts **read** the world directly: a read-only `BoardView` (a registered type with getters only — read-only by construction) is pushed into each scope as `board`, so a script writes `board.player_x`; the getter briefly borrows the shared `Board`. Scripts **write** by enqueuing `Command { source, kind }` where `kind: GameCommand` is `Move(Direction)` / `SetTile(u32)` / `Log(LogLine)` / `Error(String)`. The host fns `move`/`set_tile`/`log` push into a shared `Rc<RefCell<Vec<Command>>>` cloned into each closure (the same `'static`-closure trick the old log sink used, generalized); `GameState::apply_commands` drains and applies them after the batch. Reads-are-live, writes-are-deferred gives frame-coherent semantics and keeps script execution free of any `&mut GameState` borrow.
|
||||
**Reads vs writes.** Scripts **read** the world directly: read getters are registered on `Rc<RefCell<Board>>` (the `BoardRef` alias, exposed to Rhai as type `Board`) — getters only, so read-only by construction — and a clone of the handle is pushed into each scope as the constant `Board`, so a script writes `Board.player_x`; the getter briefly borrows the shared `Board`. Scripts **write** by enqueuing `Command { source, kind }` where `kind: GameCommand` is `Move(Direction)` / `SetTile(u32)` / `Log(LogLine)` / `Error(String)`. The host fns `move`/`set_tile`/`log` push into a shared `Rc<RefCell<Vec<Command>>>` cloned into each closure (the same `'static`-closure trick the old log sink used, generalized); `GameState::apply_commands` drains and applies them after the batch. Reads-are-live, writes-are-deferred gives frame-coherent semantics and keeps script execution free of any `&mut GameState` borrow.
|
||||
|
||||
**Sender identity** (which object issued a command) rides Rhai's per-call **tag**: `run` calls `call_fn_with_options(...with_tag(object_index)...)` and the host fns read it via `NativeCallContext::tag()`, so scripts write `move(north)` without a `this` argument (`north`/`south`/`east`/`west` are `Direction` constants in scope; `impl From<Direction> for (i32,i32)` yields the delta). The object's identity is currently its index into `Board::objects` — a stopgap (a `// TODO` flags replacing it with stable unique ids that survive spawn/destroy). Default `call_fn` rewinds the scope per call, so script-local persistence across ticks is still future work; the per-object `Scope` is the seam for that. `Engine`/`Scope` are not `Send` — fine for the single-threaded kiln-tui.
|
||||
**Sender identity** (which object issued a command) rides Rhai's per-call **tag**: `run` calls `call_fn_with_options(...with_tag(object_index)...)` and the host fns read it via `NativeCallContext::tag()`, so scripts write `move(North)` without a `this` argument (`North`/`South`/`East`/`West` are `Direction` constants in scope; `impl From<Direction> for (i32,i32)` yields the delta). The object's identity is currently its index into `Board::objects` — a stopgap (a `// TODO` flags replacing it with stable unique ids that survive spawn/destroy). Default `call_fn` rewinds the scope per call, so script-local persistence across ticks is still future work; the per-object `Scope` is the seam for that. `Engine`/`Scope` are not `Send` — fine for the single-threaded kiln-tui.
|
||||
|
||||
---
|
||||
|
||||
@@ -309,10 +309,10 @@ target_entry = "west_door"
|
||||
[scripts]
|
||||
greeter = """
|
||||
fn init() {
|
||||
log(`player at ${board.player_x}, ${board.player_y}`); # read
|
||||
log(`player at ${Board.player_x}, ${Board.player_y}`); # read
|
||||
set_tile(2); # write
|
||||
}
|
||||
fn tick(dt) { move(north); } # dt = elapsed seconds; dir ∈ north/south/east/west
|
||||
fn tick(dt) { move(North); } # dt = elapsed seconds; dir ∈ North/South/East/West
|
||||
"""
|
||||
```
|
||||
|
||||
@@ -336,7 +336,7 @@ A direct mapping from palette character → `(Glyph, Archetype)` means the map f
|
||||
|
||||
## What's not yet implemented
|
||||
|
||||
**Object scripting** — the runtime exists (`script.rs`): objects run optional `init()`/`tick(dt)` hooks, **read** the world via `board.*`, and **write** via queued commands (`move`, `set_tile`, `log`). Still to come:
|
||||
**Object scripting** — the runtime exists (`script.rs`): objects run optional `init()`/`tick(dt)` hooks, **read** the world via `Board.*`, and **write** via queued commands (`move`, `set_tile`, `log`). Still to come:
|
||||
1. More event hooks beyond lifecycle — e.g. fire `on_touch` when the player moves onto an object's cell
|
||||
2. Grow the command vocabulary and read API (`send_message`, randomness, board queries, more glyph setters)
|
||||
3. **Stable object ids** — `Command.source` / `ObjectRuntime.object_index` are array indices into `Board::objects`, which break under spawn/destroy/reorder; replace with monotonically-increasing unique ids and key objects by them (a `// TODO` marks this in code)
|
||||
|
||||
Reference in New Issue
Block a user