[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 (script_reload_send, script_reload_recv) = channel();
|
||||||
|
|
||||||
let mut script = script::ScriptContext::new(script_reload_send.clone());
|
let mut script = script::ScriptContext::new(None, script_reload_send.clone())
|
||||||
script.init();
|
.expect("Unable to create initial script context");
|
||||||
|
|
||||||
const SPF: f64 = 1.0 / 60.0;
|
const SPF: f64 = 1.0 / 60.0;
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -823,11 +823,10 @@ fn main_thread(event_loop: EventLoopProxy<OdenEvent>, state: State, reciever: Re
|
||||||
if reload_script {
|
if reload_script {
|
||||||
eprintln!("RELOADING SCRIPT");
|
eprintln!("RELOADING SCRIPT");
|
||||||
let suspend_state = script.suspend();
|
let suspend_state = script.suspend();
|
||||||
script = script::ScriptContext::new(script_reload_send.clone());
|
match script::ScriptContext::new(suspend_state, script_reload_send.clone()) {
|
||||||
script.init();
|
Ok(new_script) => script = new_script,
|
||||||
if let Some(s) = suspend_state {
|
Err(e) => eprintln!("WARNING: Script reload aborted, load failure: {e:?}"),
|
||||||
script.resume(&s);
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,11 +55,9 @@ impl ModuleLoader for Loader {
|
||||||
|
|
||||||
pub struct ScriptContext {
|
pub struct ScriptContext {
|
||||||
context: Context,
|
context: Context,
|
||||||
init: Value,
|
|
||||||
update: Value,
|
update: Value,
|
||||||
draw: Value,
|
draw: Value,
|
||||||
suspend: Value,
|
suspend: Value,
|
||||||
resume: Value,
|
|
||||||
|
|
||||||
state: Value,
|
state: Value,
|
||||||
|
|
||||||
|
|
@ -71,7 +69,7 @@ pub struct ScriptContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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();
|
let mut runtime = Runtime::new();
|
||||||
runtime.set_module_loader(Loader::new(reload_trigger));
|
runtime.set_module_loader(Loader::new(reload_trigger));
|
||||||
|
|
||||||
|
|
@ -82,41 +80,31 @@ impl ScriptContext {
|
||||||
|
|
||||||
let (gfx_send, gfx_receive) = channel();
|
let (gfx_send, gfx_receive) = channel();
|
||||||
|
|
||||||
let gfx = graphics::GraphicsAPI::define(&context, gfx_send.clone())
|
let gfx = graphics::GraphicsAPI::define(&context, gfx_send.clone())?;
|
||||||
.expect("Graphics module should load without error");
|
let _io = io::IoAPI::define(&context)?;
|
||||||
let _io = io::IoAPI::define(&context).expect("IO module should load without error");
|
let time = time::TimeAPI::define(&context)?;
|
||||||
let time = time::TimeAPI::define(&context).expect("Time module should load without error");
|
let input = input::InputAPI::define(&context)?;
|
||||||
let input =
|
|
||||||
input::InputAPI::define(&context).expect("Input module should load without error");
|
|
||||||
|
|
||||||
let module = context
|
let module = context.import_module("./main.ts", "")?;
|
||||||
.import_module("./main.ts", "")
|
|
||||||
.expect("Unable to load main");
|
|
||||||
|
|
||||||
let init = module
|
let init = module.get_export(&context, "init")?;
|
||||||
.get_export(&context, "init")
|
let suspend = module.get_export(&context, "suspend")?;
|
||||||
.expect("Unable to fetch init");
|
let resume = module.get_export(&context, "resume")?;
|
||||||
let suspend = module
|
let update = module.get_export(&context, "update")?;
|
||||||
.get_export(&context, "suspend")
|
let draw = module.get_export(&context, "draw")?;
|
||||||
.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 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,
|
context,
|
||||||
|
|
||||||
init,
|
|
||||||
suspend,
|
suspend,
|
||||||
resume,
|
|
||||||
update,
|
update,
|
||||||
draw,
|
draw,
|
||||||
|
|
||||||
|
|
@ -127,7 +115,7 @@ impl ScriptContext {
|
||||||
|
|
||||||
time,
|
time,
|
||||||
input,
|
input,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allow the script to save its state before we destroy it and re-create
|
/// 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.
|
// 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
|
// 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.
|
// 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 {
|
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
||||||
match event {
|
match event {
|
||||||
WindowEvent::KeyboardInput { input, .. } => self.input.handle_keyboard_input(input),
|
WindowEvent::KeyboardInput { input, .. } => self.input.handle_keyboard_input(input),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue