no need for scriptstate any more

This commit is contained in:
2026-07-07 23:55:27 -05:00
parent 78823fcf96
commit 23b5bf2afb
18 changed files with 146 additions and 174 deletions
+35 -41
View File
@@ -35,7 +35,7 @@ use crate::game::SAY_DURATION;
use crate::log::LogLine;
use crate::map_file::parse_color;
use crate::object_def::ObjectDef;
use crate::utils::{Direction, ErrorSink, Hook, ObjectId, RegistryValue};
use crate::utils::{Direction, ErrorSink, Hook, ObjectId};
use rhai::{
Array, CallFnOptions, Dynamic, Engine, ImmutableString, Module, NativeCallContext,
Scope, AST,
@@ -48,9 +48,9 @@ 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;
use crate::player::PlayerRef;
/// Types which can be registered to be sent to Rhai
pub trait Registerable {
@@ -100,6 +100,7 @@ pub struct ScriptHost {
scopes: HashMap<ObjectId, Scope<'static>>,
board_queue: BoardQueue,
errors: ErrorSink,
board: BoardRef
}
impl ScriptHost {
@@ -110,7 +111,7 @@ 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_cell: &BoardRef, script_sources: &HashMap<String, String>) -> Self {
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();
@@ -120,16 +121,15 @@ impl ScriptHost {
PlayerWithPos::register(&mut engine, errors.clone());
Keyring::register(&mut engine, errors.clone());
BoardRef::register(&mut engine, errors.clone());
ScriptState::register(&mut engine, errors.clone());
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_global_constants(&mut engine, board_cell.clone());
register_write_api(&mut engine, board_ref.clone());
register_global_constants(&mut engine, board_ref.clone(), player.clone());
let board = board_cell.borrow();
let board = board_ref.borrow();
// Compile each referenced script once, keyed by `script_key` (the object's
// `script_name`: a world-pool name for named scripts, or a synthetic
@@ -166,10 +166,10 @@ impl ScriptHost {
scripts.insert(
key,
CompiledScript {
has_init: defines("init", 2),
has_tick: defines("tick", 3),
has_bump: defines("bump", 3),
has_grab: defines("grab", 2),
has_init: defines("init", 1),
has_tick: defines("tick", 2),
has_bump: defines("bump", 2),
has_grab: defines("grab", 1),
ast,
},
);
@@ -199,43 +199,41 @@ impl ScriptHost {
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, state: ScriptState, dt: f64) {
self.run_hook_on_all(Hook::Tick, state, dt);
pub fn run_tick(&mut self, dt: f64) {
self.run_hook_on_all(Hook::Tick, dt);
}
pub fn run_init(&mut self, state: ScriptState) {
self.run_hook_on_all(Hook::Init, state, 0.0)
pub fn run_init(&mut self) {
self.run_hook_on_all(Hook::Init, 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, state: ScriptState, dt: f64) {
let all_ids = state.board.borrow().all_ids();
fn run_hook_on_all(&mut self, hook: Hook, dt: f64) {
let all_ids = self.board.borrow().all_ids();
let arg = match hook {
Hook::Tick => Some(Dynamic::from(dt)),
_ => None,
};
for id in all_ids {
self.run_hook_on_one(hook, state.clone(), id, arg.clone(), dt)
self.run_hook_on_one(hook, id, arg.clone(), dt)
}
}
fn run_hook_on_one(&mut self, hook: Hook, state: ScriptState, id: ObjectId, arg: Option<Dynamic>, dt: f64) {
if let Some(mut info) = ObjectInfo::from_id(id, state.board.clone()) {
fn run_hook_on_one(&mut self, hook: Hook, id: ObjectId, arg: Option<Dynamic>, dt: f64) {
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)
&& let Some(scope) = self.scopes.get_mut(&id) {
if script.has(hook) {
let mut args = vec![
Dynamic::from(info.clone()),
Dynamic::from(state.clone())
];
let mut args = vec![Dynamic::from(info.clone())];
if let Some(d) = arg { args.push(d) }
// Call this with opts tagging this call as our id. The write API will read
@@ -261,8 +259,8 @@ impl ScriptHost {
/// Calls `bump(id)` on the object with [`ObjectId`] `object_id`, if it defines
/// the hook. After the hook, drains the object's queue with `dt = 0`.
pub fn run_bump(&mut self, state: ScriptState, id: ObjectId, bumper: i64) {
self.run_hook_on_one(Hook::Bump, state, id, Some(Dynamic::from(bumper)), 0.0);
pub fn run_bump(&mut self, id: ObjectId, bumper: i64) {
self.run_hook_on_one(Hook::Bump, id, Some(Dynamic::from(bumper)), 0.0);
}
/// Calls `grab()` on the object with [`ObjectId`] `object_id`, if it defines the
@@ -271,21 +269,20 @@ impl ScriptHost {
/// 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, state: ScriptState, object_id: ObjectId) {
self.run_hook_on_one(Hook::Grab, state, object_id, None, 0.0);
pub fn run_grab(&mut self, object_id: ObjectId) {
self.run_hook_on_one(Hook::Grab, object_id, None, 0.0);
}
/// Calls the named function on the object with [`ObjectId`] `target_id`.
///
/// What we pass depends on arity, in this order:
/// - If it has arity 3, we pass `[ObjectInfo, ScriptState, SendArg]`
/// - If it has arity 2, we pass `[ObjectInfo, ScriptState]`
/// - If it has arity 1, we pass the arg
/// - If it has arity 2, we pass `[ObjectInfo, arg]`
/// - 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, state: ScriptState, id: ObjectId, fn_name: &str, arg: SendArg) {
if let Some(mut info) = ObjectInfo::from_id(id, state.board.clone()) {
pub(crate) fn run_send(&mut self, id: ObjectId, fn_name: &str, arg: SendArg) {
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)
&& let Some(scope) = self.scopes.get_mut(&id) {
@@ -307,15 +304,11 @@ impl ScriptHost {
// Assemble the args
let mut args = vec![];
if arities.contains(&3) {
if arities.contains(&2) {
args.push(Dynamic::from(info.clone()));
args.push(Dynamic::from(state.clone()));
args.push(arg.into());
} else if arities.contains(&2) {
args.push(Dynamic::from(info.clone()));
args.push(Dynamic::from(state.clone()));
} else if arities.contains(&1) {
args.push(arg.into());
args.push(Dynamic::from(info.clone()));
}
// Call this with opts tagging this call as our id. The write API will read
@@ -614,9 +607,10 @@ 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, board: BoardRef) {
fn register_global_constants(engine: &mut Engine, board: BoardRef, player: PlayerRef) {
let mut m = Module::new();
m.set_var("Board", board);
m.set_var("Board", board.clone());
m.set_var("Player", PlayerWithPos(player.clone(), board));
m.set_var("North", Direction::North);
m.set_var("South", Direction::South);
m.set_var("East", Direction::East);