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
+4
View File
@@ -17,6 +17,7 @@ use std::rc::Rc;
use rhai::{Dynamic, Engine, ImmutableString};
use crate::{Board, Direction};
use crate::api::object_info::ObjectInfo;
use crate::api::registry::Registry;
use crate::script::Registerable;
use crate::utils::{ErrorSink, ObjectId};
@@ -90,5 +91,8 @@ impl Registerable for BoardRef {
.collect()
},
);
// Board.registry -> Registry
engine.register_get("registry", |b: &mut BoardRef| Registry(b.clone()));
}
}
+1
View File
@@ -3,3 +3,4 @@ pub mod player;
pub mod board;
pub mod object_info;
pub mod queue;
pub mod registry;
+5 -1
View File
@@ -73,13 +73,17 @@ impl ObjQueue {
pub fn waiting(&mut self) -> bool {
matches!(self.0.borrow().front(), Some(Action::Delay(_)))
}
pub fn clear(&mut self) {
self.0.borrow_mut().clear();
}
}
impl Registerable for ObjQueue {
fn register(engine: &mut Engine, error_sink: ErrorSink) {
engine.register_type_with_name::<ObjQueue>("Queue");
engine.register_get("length", |q: &mut ObjQueue| q.0.borrow().len() as i64);
engine.register_fn("clear", |q: &mut ObjQueue| q.0.borrow_mut().clear());
engine.register_fn("clear", ObjQueue::clear);
// Appends a [`Action::Delay`] to the back of `queue`, merging with an existing
// trailing delay to prevent adjacent delays from accumulating.
+63
View File
@@ -0,0 +1,63 @@
use rhai::{Dynamic, Engine, ImmutableString};
use crate::api::board::BoardRef;
use crate::script::Registerable;
use crate::utils::{ErrorSink, RegistryValue};
/// 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)]
pub struct Registry(pub BoardRef);
impl Registerable for Registry {
fn register(engine: &mut Engine, error_sink: ErrorSink) {
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.0
.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.0.borrow_mut().registry.insert(key.to_string(), rv);
}
Err(()) if value.is_unit() => {
r.0.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.0.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
}
},
);
}
}