[oden] Hot-reload script files
This commit is contained in:
parent
642ced45f8
commit
a850c3cc58
7 changed files with 241 additions and 9 deletions
|
|
@ -1,9 +1,11 @@
|
|||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use oden_js::{
|
||||
module::loader::{ModuleLoader, ModuleSource},
|
||||
Context, ContextRef, Result, Runtime, Value,
|
||||
};
|
||||
use std::ffi::OsStr;
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
use tracy_client::span;
|
||||
use winit::event::*;
|
||||
|
|
@ -18,11 +20,19 @@ use graphics::GraphicsCommand;
|
|||
mod typescript;
|
||||
use typescript::transpile_to_javascript;
|
||||
|
||||
struct Loader {}
|
||||
struct Loader {
|
||||
watcher: Arc<Mutex<RecommendedWatcher>>,
|
||||
}
|
||||
|
||||
impl Loader {
|
||||
pub fn new() -> Loader {
|
||||
Loader {}
|
||||
pub fn new(reload_trigger: Sender<()>) -> Loader {
|
||||
let watcher = Arc::new(Mutex::new(
|
||||
notify::recommended_watcher(move |_| {
|
||||
let _ = reload_trigger.send(());
|
||||
})
|
||||
.expect("Unable to create watcher"),
|
||||
));
|
||||
Loader { watcher }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -37,6 +47,8 @@ impl ModuleLoader for Loader {
|
|||
contents
|
||||
};
|
||||
|
||||
let mut watcher = self.watcher.lock().unwrap();
|
||||
let _ = watcher.watch(&path, RecursiveMode::NonRecursive);
|
||||
Ok(ModuleSource::JavaScript(contents))
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +58,8 @@ pub struct ScriptContext {
|
|||
init: Value,
|
||||
update: Value,
|
||||
draw: Value,
|
||||
suspend: Value,
|
||||
resume: Value,
|
||||
|
||||
state: Value,
|
||||
|
||||
|
|
@ -57,9 +71,9 @@ pub struct ScriptContext {
|
|||
}
|
||||
|
||||
impl ScriptContext {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(reload_trigger: Sender<()>) -> Self {
|
||||
let mut runtime = Runtime::new();
|
||||
runtime.set_module_loader(Loader::new());
|
||||
runtime.set_module_loader(Loader::new(reload_trigger));
|
||||
|
||||
let mut context = Context::new(runtime);
|
||||
context.add_intrinsic_bigfloat();
|
||||
|
|
@ -82,6 +96,12 @@ impl ScriptContext {
|
|||
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");
|
||||
|
|
@ -95,6 +115,8 @@ impl ScriptContext {
|
|||
context,
|
||||
|
||||
init,
|
||||
suspend,
|
||||
resume,
|
||||
update,
|
||||
draw,
|
||||
|
||||
|
|
@ -108,6 +130,42 @@ impl ScriptContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Allow the script to save its state before we destroy it and re-create
|
||||
/// it.
|
||||
pub fn suspend(&self) -> Option<Vec<u8>> {
|
||||
let _span = span!("script suspend");
|
||||
if !self.suspend.is_undefined() {
|
||||
let suspend_state = self
|
||||
.suspend
|
||||
.call(&self.context, &[&self.state])
|
||||
.expect("Exception in suspend");
|
||||
Some(
|
||||
suspend_state
|
||||
.serialize(&self.context)
|
||||
.expect("Unable to serialize state"),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue