drain object queues after each object
This commit is contained in:
+38
-43
@@ -40,9 +40,7 @@ use rhai::{
|
||||
Array, CallFnOptions, Dynamic, Engine, ImmutableString, Module, NativeCallContext,
|
||||
Scope, AST,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::rc::Rc;
|
||||
use crate::api::board::BoardRef;
|
||||
use crate::api::object_info::ObjectInfo;
|
||||
use crate::api::player::PlayerWithPos;
|
||||
@@ -58,9 +56,6 @@ pub trait Registerable {
|
||||
fn register(engine: &mut Engine, error_sink: ErrorSink);
|
||||
}
|
||||
|
||||
/// The board queue: actions promoted from object queues, awaiting resolution.
|
||||
pub type BoardQueue = Rc<RefCell<Vec<BoardAction>>>;
|
||||
|
||||
/// A compiled script plus which lifecycle hooks it defines.
|
||||
struct CompiledScript {
|
||||
ast: AST,
|
||||
@@ -98,7 +93,6 @@ pub struct ScriptHost {
|
||||
engine: Engine,
|
||||
scripts: HashMap<String, CompiledScript>,
|
||||
scopes: HashMap<ObjectId, Scope<'static>>,
|
||||
board_queue: BoardQueue,
|
||||
errors: ErrorSink,
|
||||
board: BoardRef
|
||||
}
|
||||
@@ -112,7 +106,6 @@ impl ScriptHost {
|
||||
/// `scripts` is the world-level script pool (script name → Rhai source); it is
|
||||
/// read only during construction and not retained afterward.
|
||||
pub fn new(board_ref: BoardRef, player: PlayerRef, script_sources: &HashMap<String, String>) -> Self {
|
||||
let board_queue: BoardQueue = Rc::new(RefCell::new(Vec::new()));
|
||||
let errors = ErrorSink::new();
|
||||
let mut scopes = HashMap::new();
|
||||
|
||||
@@ -196,37 +189,41 @@ impl ScriptHost {
|
||||
Self {
|
||||
engine,
|
||||
scripts,
|
||||
board_queue,
|
||||
errors,
|
||||
scopes,
|
||||
board: board_ref
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls `tick(dt)` on every scripted object that defines it, then drains queues.
|
||||
pub fn run_tick(&mut self, dt: f64) {
|
||||
self.run_hook_on_all(Hook::Tick, dt);
|
||||
/// Runs the `tick(me, dt)` hook on one object and returns the actions it
|
||||
/// drained (see [`run_hook_on_one`](ScriptHost::run_hook_on_one)).
|
||||
pub(crate) fn run_tick_on(&mut self, id: ObjectId, dt: f64) -> Vec<BoardAction> {
|
||||
self.run_hook_on(Hook::Tick, id, dt)
|
||||
}
|
||||
|
||||
pub fn run_init(&mut self) {
|
||||
self.run_hook_on_all(Hook::Init, 0.0)
|
||||
/// Runs the `init(me)` hook on one object and returns the actions it drained.
|
||||
pub(crate) fn run_init_on(&mut self, id: ObjectId) -> Vec<BoardAction> {
|
||||
self.run_hook_on(Hook::Init, id, 0.0)
|
||||
}
|
||||
|
||||
/// Run the given hook on every object that defines it. For hooks other than
|
||||
/// `Tick`, dt should just be 0.0
|
||||
fn run_hook_on_all(&mut self, hook: Hook, dt: f64) {
|
||||
let all_ids = self.board.borrow().all_ids();
|
||||
/// Runs `hook` on the single object `id` and returns the actions it drained.
|
||||
///
|
||||
/// The `dt` arg is only meaningful for `Tick` (it becomes the hook's `dt`
|
||||
/// parameter and paces the object's delay draining); pass `0.0` otherwise.
|
||||
pub(crate) fn run_hook_on(&mut self, hook: Hook, id: ObjectId, dt: f64) -> Vec<BoardAction> {
|
||||
let arg = match hook {
|
||||
Hook::Tick => Some(Dynamic::from(dt)),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
for id in all_ids {
|
||||
self.run_hook_on_one(hook, id, arg.clone(), dt)
|
||||
}
|
||||
self.run_hook_on_one(hook, id, arg, dt)
|
||||
}
|
||||
|
||||
fn run_hook_on_one(&mut self, hook: Hook, id: ObjectId, arg: Option<Dynamic>, dt: f64) {
|
||||
/// Calls one lifecycle `hook` on object `id` (if the script defines it), then
|
||||
/// drains that object's ready actions into a fresh `Vec` and returns them —
|
||||
/// [`GameState`](crate::game::GameState) applies them immediately, before the
|
||||
/// next object runs, so each object sees the board state its actions run against.
|
||||
fn run_hook_on_one(&mut self, hook: Hook, id: ObjectId, arg: Option<Dynamic>, dt: f64) -> Vec<BoardAction> {
|
||||
let mut actions = Vec::new();
|
||||
if let Some(mut info) = ObjectInfo::from_id(id, self.board.clone()) {
|
||||
if let Some(script_key) = info.script_name.as_ref()
|
||||
&& let Some(script) = self.scripts.get(script_key)
|
||||
@@ -250,29 +247,29 @@ impl ScriptHost {
|
||||
}
|
||||
// Run the drain regardless of if we have the hook, otherwise
|
||||
// things with no tick will never advance past a delay
|
||||
info.drain(self.board_queue.clone(), dt)
|
||||
info.drain(&mut actions, dt)
|
||||
}
|
||||
} else {
|
||||
unreachable!("Object not found");
|
||||
}
|
||||
actions
|
||||
}
|
||||
|
||||
/// Calls `bump(dir)` on the object with [`ObjectId`] `id`, if it defines the
|
||||
/// hook. `dir` is the [`Direction`] the bump came *from* (it points from the
|
||||
/// bumped object toward the bumper). After the hook, drains the object's queue
|
||||
/// with `dt = 0`.
|
||||
pub fn run_bump(&mut self, id: ObjectId, dir: Direction) {
|
||||
self.run_hook_on_one(Hook::Bump, id, Some(Dynamic::from(dir)), 0.0);
|
||||
/// hook, and returns the actions it drained. `dir` is the [`Direction`] the
|
||||
/// bump came *from* (it points from the bumped object toward the bumper).
|
||||
pub(crate) fn run_bump(&mut self, id: ObjectId, dir: Direction) -> Vec<BoardAction> {
|
||||
self.run_hook_on_one(Hook::Bump, id, Some(Dynamic::from(dir)), 0.0)
|
||||
}
|
||||
|
||||
/// Calls `grab()` on the object with [`ObjectId`] `object_id`, if it defines the
|
||||
/// hook, then drains its queue with `dt = 0`.
|
||||
/// hook, and returns the actions it drained.
|
||||
///
|
||||
/// Fired when the player walks onto a grab object or a grab object is pushed
|
||||
/// into the player (see [`GameState`](crate::game::GameState)). The hook
|
||||
/// typically increments a player stat and removes the object via `die()`.
|
||||
pub fn run_grab(&mut self, object_id: ObjectId) {
|
||||
self.run_hook_on_one(Hook::Grab, object_id, None, 0.0);
|
||||
/// Fired when the player walks onto a grab object (see
|
||||
/// [`GameState`](crate::game::GameState)). The hook typically increments a
|
||||
/// player stat and removes the object via `die()`.
|
||||
pub(crate) fn run_grab(&mut self, object_id: ObjectId) -> Vec<BoardAction> {
|
||||
self.run_hook_on_one(Hook::Grab, object_id, None, 0.0)
|
||||
}
|
||||
|
||||
/// Calls the named function on the object with [`ObjectId`] `target_id`.
|
||||
@@ -282,8 +279,10 @@ impl ScriptHost {
|
||||
/// - If it has arity 1, we pass the ObjectInfo alone
|
||||
/// - If it has arity 0, we pass nothing
|
||||
///
|
||||
/// In cases where the arg isn't provided but we have the arity, we pass `Dynamic::UNIT`
|
||||
pub(crate) fn run_send(&mut self, id: ObjectId, fn_name: &str, arg: SendArg) {
|
||||
/// In cases where the arg isn't provided but we have the arity, we pass `Dynamic::UNIT`.
|
||||
/// Returns the actions the call drained.
|
||||
pub(crate) fn run_send(&mut self, id: ObjectId, fn_name: &str, arg: SendArg) -> Vec<BoardAction> {
|
||||
let mut actions = Vec::new();
|
||||
if let Some(mut info) = ObjectInfo::from_id(id, self.board.clone()) {
|
||||
if let Some(script_key) = info.script_name.as_ref()
|
||||
&& let Some(script) = self.scripts.get(script_key)
|
||||
@@ -301,7 +300,7 @@ impl ScriptHost {
|
||||
// If it's not there at all, just bail:
|
||||
if arities.is_empty() {
|
||||
self.errors.error(format!("script '{}' send({}) error: function not found", script_key, fn_name));
|
||||
return
|
||||
return actions;
|
||||
}
|
||||
|
||||
// Assemble the args
|
||||
@@ -324,16 +323,12 @@ impl ScriptHost {
|
||||
) {
|
||||
self.errors.error(format!("script '{}' send({}) error: {err}", script_key, fn_name));
|
||||
}
|
||||
info.drain(self.board_queue.clone(), 0.0)
|
||||
info.drain(&mut actions, 0.0)
|
||||
}
|
||||
} else {
|
||||
unreachable!("Object id not found, tried to send");
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes and returns the actions promoted onto the board queue.
|
||||
pub(crate) fn take_board_queue(&mut self) -> Vec<BoardAction> {
|
||||
std::mem::take(&mut self.board_queue.borrow_mut())
|
||||
actions
|
||||
}
|
||||
|
||||
/// Removes and returns the errors collected since the last drain.
|
||||
|
||||
Reference in New Issue
Block a user