[oden] Catch and render script errors, stop crashing
This is kinda nice actually
This commit is contained in:
parent
a08bc07cbb
commit
22732c2b05
2 changed files with 72 additions and 30 deletions
|
|
@ -41,7 +41,7 @@ pub enum Error {
|
|||
ConversionError(String),
|
||||
#[error("an error occurred calling a rust function: {0}")]
|
||||
RustFunctionError(String),
|
||||
#[error("an exception was thrown during evaluation: {1}\nStack: {2}")]
|
||||
#[error("an exception was thrown during evaluation: {1}\nStack:\n{2}")]
|
||||
Exception(Value, String, String),
|
||||
#[error("out of memory")]
|
||||
OutOfMemory,
|
||||
|
|
|
|||
100
src/script.rs
100
src/script.rs
|
|
@ -15,7 +15,7 @@ mod input;
|
|||
mod io;
|
||||
mod time;
|
||||
|
||||
use graphics::GraphicsCommand;
|
||||
use graphics::{ClearCommand, GraphicsCommand, PrintCommand};
|
||||
|
||||
mod typescript;
|
||||
use typescript::transpile_to_javascript;
|
||||
|
|
@ -66,6 +66,8 @@ pub struct ScriptContext {
|
|||
|
||||
time: time::TimeAPI,
|
||||
input: input::InputAPI,
|
||||
|
||||
error_lines: Vec<String>,
|
||||
}
|
||||
|
||||
impl ScriptContext {
|
||||
|
|
@ -115,6 +117,8 @@ impl ScriptContext {
|
|||
|
||||
time,
|
||||
input,
|
||||
|
||||
error_lines: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -123,15 +127,17 @@ impl ScriptContext {
|
|||
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"),
|
||||
)
|
||||
match self.suspend.call(&self.context, &[&self.state]) {
|
||||
Ok(suspend_state) => Some(
|
||||
suspend_state
|
||||
.serialize(&self.context)
|
||||
.expect("Unable to serialize state"),
|
||||
),
|
||||
Err(e) => {
|
||||
eprintln!("WARNING: Error during suspend, state will not be saved: {e}");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -151,6 +157,10 @@ impl ScriptContext {
|
|||
pub fn update(&mut self) {
|
||||
let _span = span!("script update");
|
||||
|
||||
if self.error_lines.len() > 0 {
|
||||
return; // Don't bother, nothing.
|
||||
}
|
||||
|
||||
// Do we update the frame time before of after async completion?
|
||||
// Hmmmmm.
|
||||
self.time.set_frame_time(Instant::now());
|
||||
|
|
@ -159,37 +169,69 @@ impl ScriptContext {
|
|||
// promise completions.
|
||||
{
|
||||
let _span = span!("process jobs");
|
||||
self.context
|
||||
.process_all_jobs()
|
||||
.expect("Error processing async jobs");
|
||||
self.handle_result(self.context.process_all_jobs());
|
||||
}
|
||||
|
||||
// Now run the update function.
|
||||
{
|
||||
if self.error_lines.len() == 0 {
|
||||
let _span = span!("javascript update");
|
||||
let old_state = &self.state;
|
||||
self.state = self
|
||||
.update
|
||||
.call(&self.context, &[old_state])
|
||||
.expect("Exception in update");
|
||||
self.state = match self.update.call(&self.context, &[old_state]) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
self.handle_error(e);
|
||||
self.context.null()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&mut self) -> Vec<graphics::GraphicsCommand> {
|
||||
let _span = span!("script render");
|
||||
if self.error_lines.len() > 0 {
|
||||
// TODO: Use font 0 for a fallback.
|
||||
let mut commands = vec![
|
||||
GraphicsCommand::Clear(ClearCommand {
|
||||
color: [0.0, 0.0, 1.0, 1.0],
|
||||
}),
|
||||
GraphicsCommand::Print(PrintCommand {
|
||||
text: "FATAL SCRIPT ERROR".to_owned(),
|
||||
pos: [6.0, 6.0],
|
||||
}),
|
||||
];
|
||||
|
||||
self.draw
|
||||
.call(&self.context, &[&self.state])
|
||||
.expect("Exception in draw");
|
||||
self.gfx.end_frame();
|
||||
|
||||
let mut commands = Vec::new();
|
||||
loop {
|
||||
match self.gfx_receive.recv().unwrap() {
|
||||
GraphicsCommand::EndFrame => break,
|
||||
other => commands.push(other),
|
||||
let mut y = 20.0;
|
||||
for line in &self.error_lines {
|
||||
commands.push(GraphicsCommand::Print(PrintCommand {
|
||||
text: line.clone(),
|
||||
pos: [6.0, y],
|
||||
}));
|
||||
y += 8.0;
|
||||
}
|
||||
|
||||
commands
|
||||
} else {
|
||||
self.handle_result(self.draw.call(&self.context, &[&self.state]));
|
||||
self.gfx.end_frame();
|
||||
|
||||
let mut commands = Vec::new();
|
||||
loop {
|
||||
match self.gfx_receive.recv().unwrap() {
|
||||
GraphicsCommand::EndFrame => break,
|
||||
other => commands.push(other),
|
||||
}
|
||||
}
|
||||
commands
|
||||
}
|
||||
commands
|
||||
}
|
||||
|
||||
fn handle_result<T>(&mut self, result: Result<T>) {
|
||||
if let Err(e) = result {
|
||||
self.handle_error(e);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_error(&mut self, error: oden_js::Error) {
|
||||
self.error_lines = error.to_string().lines().map(|l| l.to_owned()).collect();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue