Registry refactor and clear queues on board entry

This commit is contained in:
2026-07-06 00:41:38 -05:00
parent b7063277e7
commit 78823fcf96
9 changed files with 97 additions and 85 deletions
+6 -77
View File
@@ -47,6 +47,7 @@ use crate::api::board::BoardRef;
use crate::api::object_info::ObjectInfo;
use crate::api::player::PlayerWithPos;
use crate::api::queue::ObjQueue;
use crate::api::registry::Registry;
use crate::api::state::ScriptState;
use crate::glyph::Glyph;
use crate::keys::Keyring;
@@ -90,18 +91,6 @@ fn script_key(obj: &ObjectDef) -> Option<String> {
obj.script_name.clone()
}
// ── Rhai types exposed to scripts ────────────────────────────────────────────
/// The board's script registry, pushed into scope as the constant `Registry`.
/// `get`/`set`/`get_or` methods let scripts read and write per-board key→value pairs
/// that persist across board transitions. Mutation goes through the inner
/// `Rc<RefCell<Board>>`, so the struct itself can be shared as a scope constant.
#[derive(Clone)]
struct Registry {
board: BoardRef,
}
// ── ScriptHost ────────────────────────────────────────────────────────────────
/// Owns the Rhai engine and per-object script state for a board.
@@ -135,10 +124,10 @@ impl ScriptHost {
ObjectInfo::register(&mut engine, errors.clone());
Glyph::register(&mut engine, errors.clone());
ObjQueue::register(&mut engine, errors.clone());
Registry::register(&mut engine, errors.clone());
register_write_api(&mut engine, board_cell.clone());
register_registry_type(&mut engine);
register_global_constants(&mut engine);
register_global_constants(&mut engine, board_cell.clone());
let board = board_cell.borrow();
@@ -200,7 +189,7 @@ impl ScriptHost {
if !scripts.contains_key(&key) {
continue;
}
scopes.insert(id, new_object_scope(board_cell));
scopes.insert(id, Scope::new());
}
drop(board);
@@ -358,58 +347,6 @@ impl ScriptHost {
}
}
// ── Register Registry type ────────────────────────────────────────────────────
fn register_registry_type(engine: &mut Engine) {
engine.register_type_with_name::<Registry>("Registry");
// Registry.get(key) -> Dynamic — returns () if the key is absent.
engine.register_fn("get", |r: &mut Registry, key: ImmutableString| -> Dynamic {
r.board
.borrow()
.registry
.get(key.as_str())
.map(|v| v.clone().into())
.unwrap_or(Dynamic::UNIT)
});
// Registry.set(key, value) — stores a primitive value; () removes the key;
// unsupported types (closures, custom objects) are silently ignored.
engine.register_fn(
"set",
|r: &mut Registry, key: ImmutableString, value: Dynamic| {
match RegistryValue::try_from(value.clone()) {
Ok(rv) => {
r.board.borrow_mut().registry.insert(key.to_string(), rv);
}
Err(()) if value.is_unit() => {
r.board.borrow_mut().registry.remove(key.as_str());
}
Err(()) => {} // unsupported type — silently ignore
}
},
);
// Registry.get_or(key, default) — returns the stored value when present and the
// same Rhai type as `default`; falls back to `default` otherwise.
engine.register_fn(
"get_or",
|r: &mut Registry, key: ImmutableString, default: Dynamic| -> Dynamic {
if let Some(stored) = r.board.borrow().registry.get(key.as_str()).cloned() {
let candidate: Dynamic = stored.into();
// Only return the stored value if it matches the type of the default.
if candidate.type_id() == default.type_id() {
candidate
} else {
default
}
} else {
default
}
},
);
}
// ── Write API ─────────────────────────────────────────────────────────────────
fn register_write_api(engine: &mut Engine, board: BoardRef) {
@@ -677,8 +614,9 @@ fn read_coord_array(arr: &Array) -> Result<Vec<(i64, i64)>, ()> {
/// Registers direction and color constants as a global Rhai module so they are
/// visible to every function at any call depth, including Rhai-to-Rhai calls.
/// (Scope-level constants are only visible to the top-level function Rust calls.)
fn register_global_constants(engine: &mut Engine) {
fn register_global_constants(engine: &mut Engine, board: BoardRef) {
let mut m = Module::new();
m.set_var("Board", board);
m.set_var("North", Direction::North);
m.set_var("South", Direction::South);
m.set_var("East", Direction::East);
@@ -691,15 +629,6 @@ fn register_global_constants(engine: &mut Engine) {
engine.register_global_module(m.into());
}
/// Builds a fresh per-object scope containing only the `Registry` handle. The
/// per-object `me` (an [`ObjectInfo`]) and `state` (a [`ScriptState`]) views are
/// passed as hook parameters, not scope constants.
fn new_object_scope(board: &BoardRef) -> Scope<'static> {
let mut scope = Scope::new();
scope.push_constant("Registry", Registry { board: board.clone() });
scope
}
/// Appends `action` to the output queue of the object identified by `source`.
fn emit(board: &BoardRef, source: ObjectId, action: Action) {
if let Some(def) = board.borrow_mut().objects.get_mut(&source) {