[oden] Tolerate bad scripts on hot reload
When the script changes from under us it might be bugged for some reason; just let that be for now, ignore the load, and hopefully the engineer will fix it, eventually.
This commit is contained in:
parent
d79b891b7b
commit
e32643486d
2 changed files with 26 additions and 65 deletions
13
src/lib.rs
13
src/lib.rs
|
|
@ -768,8 +768,8 @@ fn main_thread(event_loop: EventLoopProxy<OdenEvent>, state: State, reciever: Re
|
|||
|
||||
let (script_reload_send, script_reload_recv) = channel();
|
||||
|
||||
let mut script = script::ScriptContext::new(script_reload_send.clone());
|
||||
script.init();
|
||||
let mut script = script::ScriptContext::new(None, script_reload_send.clone())
|
||||
.expect("Unable to create initial script context");
|
||||
|
||||
const SPF: f64 = 1.0 / 60.0;
|
||||
loop {
|
||||
|
|
@ -823,11 +823,10 @@ fn main_thread(event_loop: EventLoopProxy<OdenEvent>, state: State, reciever: Re
|
|||
if reload_script {
|
||||
eprintln!("RELOADING SCRIPT");
|
||||
let suspend_state = script.suspend();
|
||||
script = script::ScriptContext::new(script_reload_send.clone());
|
||||
script.init();
|
||||
if let Some(s) = suspend_state {
|
||||
script.resume(&s);
|
||||
}
|
||||
match script::ScriptContext::new(suspend_state, script_reload_send.clone()) {
|
||||
Ok(new_script) => script = new_script,
|
||||
Err(e) => eprintln!("WARNING: Script reload aborted, load failure: {e:?}"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,11 +55,9 @@ impl ModuleLoader for Loader {
|
|||
|
||||
pub struct ScriptContext {
|
||||
context: Context,
|
||||
init: Value,
|
||||
update: Value,
|
||||
draw: Value,
|
||||
suspend: Value,
|
||||
resume: Value,
|
||||
|
||||
state: Value,
|
||||
|
||||
|
|
@ -71,7 +69,7 @@ pub struct ScriptContext {
|
|||
}
|
||||
|
||||
impl ScriptContext {
|
||||
pub fn new(reload_trigger: Sender<()>) -> Self {
|
||||
pub fn new(suspend_state: Option<Vec<u8>>, reload_trigger: Sender<()>) -> Result<Self> {
|
||||
let mut runtime = Runtime::new();
|
||||
runtime.set_module_loader(Loader::new(reload_trigger));
|
||||
|
||||
|
|
@ -82,41 +80,31 @@ impl ScriptContext {
|
|||
|
||||
let (gfx_send, gfx_receive) = channel();
|
||||
|
||||
let gfx = graphics::GraphicsAPI::define(&context, gfx_send.clone())
|
||||
.expect("Graphics module should load without error");
|
||||
let _io = io::IoAPI::define(&context).expect("IO module should load without error");
|
||||
let time = time::TimeAPI::define(&context).expect("Time module should load without error");
|
||||
let input =
|
||||
input::InputAPI::define(&context).expect("Input module should load without error");
|
||||
let gfx = graphics::GraphicsAPI::define(&context, gfx_send.clone())?;
|
||||
let _io = io::IoAPI::define(&context)?;
|
||||
let time = time::TimeAPI::define(&context)?;
|
||||
let input = input::InputAPI::define(&context)?;
|
||||
|
||||
let module = context
|
||||
.import_module("./main.ts", "")
|
||||
.expect("Unable to load main");
|
||||
let module = context.import_module("./main.ts", "")?;
|
||||
|
||||
let init = module
|
||||
.get_export(&context, "init")
|
||||
.expect("Unable to fetch init");
|
||||
let suspend = module
|
||||
.get_export(&context, "suspend")
|
||||
.expect("Unable to fetch suspend");
|
||||
let resume = module
|
||||
.get_export(&context, "resume")
|
||||
.expect("Unable to fetch suspend");
|
||||
let update = module
|
||||
.get_export(&context, "update")
|
||||
.expect("Unable to fetch update");
|
||||
let draw = module
|
||||
.get_export(&context, "draw")
|
||||
.expect("Unable to fetch draw");
|
||||
let init = module.get_export(&context, "init")?;
|
||||
let suspend = module.get_export(&context, "suspend")?;
|
||||
let resume = module.get_export(&context, "resume")?;
|
||||
let update = module.get_export(&context, "update")?;
|
||||
let draw = module.get_export(&context, "draw")?;
|
||||
|
||||
let state = context.undefined();
|
||||
let mut state = init.call(&context, &[])?;
|
||||
if let Some(buffer) = suspend_state {
|
||||
if !resume.is_undefined() {
|
||||
let serialized_state = context.deserialize(&buffer)?;
|
||||
state = resume.call(&context, &[&serialized_state, &state])?;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptContext {
|
||||
Ok(ScriptContext {
|
||||
context,
|
||||
|
||||
init,
|
||||
suspend,
|
||||
resume,
|
||||
update,
|
||||
draw,
|
||||
|
||||
|
|
@ -127,7 +115,7 @@ impl ScriptContext {
|
|||
|
||||
time,
|
||||
input,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Allow the script to save its state before we destroy it and re-create
|
||||
|
|
@ -149,36 +137,10 @@ impl ScriptContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Allow the script to restore its state after being destroyed and
|
||||
/// re-created.
|
||||
pub fn resume(&mut self, state: &[u8]) {
|
||||
let _span = span!("script resume");
|
||||
if !self.resume.is_undefined() {
|
||||
let suspend_state = self
|
||||
.context
|
||||
.deserialize(state)
|
||||
.expect("Unable to deserialize state");
|
||||
let prev_state = self.state.clone();
|
||||
self.state = self
|
||||
.resume
|
||||
.call(&self.context, &[&suspend_state, &prev_state])
|
||||
.expect("Exception in resume");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The script could really be on a background thread you know.
|
||||
// We would want a bi-directional gate for frames to not let the
|
||||
// game thread go to fast probably? And to discard whole frames &c.
|
||||
|
||||
pub fn init(&mut self) {
|
||||
let _span = span!("script init");
|
||||
|
||||
self.state = self
|
||||
.init
|
||||
.call(&self.context, &[])
|
||||
.expect("Exception in init");
|
||||
}
|
||||
|
||||
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
||||
match event {
|
||||
WindowEvent::KeyboardInput { input, .. } => self.input.handle_keyboard_input(input),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue