pub trait ObjectScript: 'static {
fn on_start(&mut self, id: usize, world: &mut crate::world::World) {
let _ = (id, world);
}
fn on_update(&mut self, id: usize, world: &mut crate::world::World, dt: f32) {
let _ = (id, world, dt);
}
fn on_fixed_update(&mut self, id: usize, world: &mut crate::world::World, dt: f32) {
let _ = (id, world, dt);
}
}
struct ScriptEntry {
id: usize,
script: Box<dyn ObjectScript>,
started: bool,
}
#[derive(Default)]
pub struct ScriptRegistry {
entries: Vec<ScriptEntry>,
index: std::collections::HashMap<usize, usize>,
}
impl ScriptRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn attach(&mut self, id: usize, script: Box<dyn ObjectScript>) {
if let Some(&idx) = self.index.get(&id) {
self.entries[idx].script = script;
self.entries[idx].started = false;
} else {
let idx = self.entries.len();
self.entries.push(ScriptEntry { id, script, started: false });
self.index.insert(id, idx);
}
}
pub fn detach(&mut self, id: usize) -> bool {
let Some(idx) = self.index.remove(&id) else { return false; };
let last_idx = self.entries.len() - 1;
if idx != last_idx {
self.entries.swap(idx, last_idx);
let moved_id = self.entries[idx].id;
self.index.insert(moved_id, idx);
}
self.entries.pop();
true
}
pub fn has(&self, id: usize) -> bool {
self.index.contains_key(&id)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn reset_started(&mut self) {
for entry in &mut self.entries {
entry.started = false;
}
}
pub(crate) fn run_update(&mut self, world: &mut crate::world::World, dt: f32) {
if self.entries.is_empty() { return; }
let mut i = 0;
while i < self.entries.len() {
let id = self.entries[i].id;
if !world.objects.contains_key(&id) {
self.prune_at(i);
} else {
{
let entry = &mut self.entries[i];
if !entry.started {
entry.script.on_start(id, world);
entry.started = true;
}
entry.script.on_update(id, world, dt);
}
i += 1;
}
}
}
pub(crate) fn run_fixed_update(&mut self, world: &mut crate::world::World, dt: f32) {
if self.entries.is_empty() { return; }
let mut i = 0;
while i < self.entries.len() {
let id = self.entries[i].id;
if !world.objects.contains_key(&id) {
self.prune_at(i);
} else {
{
let entry = &mut self.entries[i];
if !entry.started {
entry.script.on_start(id, world);
entry.started = true;
}
entry.script.on_fixed_update(id, world, dt);
}
i += 1;
}
}
}
fn prune_at(&mut self, i: usize) {
let id = self.entries[i].id;
self.index.remove(&id);
let last = self.entries.len() - 1;
if i != last {
self.entries.swap(i, last);
let moved_id = self.entries[i].id;
self.index.insert(moved_id, i);
}
self.entries.pop();
}
}