warpack_core/
lib.rs

1#![allow(dead_code)]
2
3extern crate warpack_stock_data as w3data;
4extern crate ceres_mpq as mpq;
5
6use std::error::Error;
7use std::fs;
8use std::path::PathBuf;
9use std::rc::Rc;
10
11use rlua::prelude::*;
12
13use crate::error::ContextError;
14use crate::evloop::wait_on_evloop;
15
16pub(crate) mod lua;
17pub(crate) mod error;
18pub(crate) mod compiler;
19pub(crate) mod evloop;
20
21#[derive(Copy, Clone)]
22pub enum WarpackRunMode {
23    Build,
24    RunMap,
25    LiveReload,
26}
27
28pub fn lua_error_root_cause(error: &LuaError) -> anyhow::Error {
29    match error {
30        LuaError::CallbackError { traceback, cause } => {
31            anyhow::anyhow!("{}\n{}", lua_error_root_cause(cause), traceback)
32        }
33        LuaError::ExternalError(external) => {
34            if let Some(error) = <dyn Error>::downcast_ref::<LuaError>(external.as_ref()) {
35                lua_error_root_cause(error)
36            } else {
37                anyhow::anyhow!("{}", external)
38            }
39        }
40        other => anyhow::anyhow!("{}", other),
41    }
42}
43
44pub fn handle_lua_result(result: anyhow::Result<()>) {
45    if let Err(err) = result {
46        match err.downcast::<LuaError>() {
47            Ok(err) => {
48                println!("{}", lua_error_root_cause(&err));
49            }
50            Err(err) => println!("{}", err),
51        }
52    }
53}
54
55pub fn execute_script<F>(
56    run_mode: WarpackRunMode,
57    script_args: Vec<&str>,
58    action: F,
59) -> Result<(), anyhow::Error>
60where
61    F: FnOnce(LuaContext) -> Result<(), anyhow::Error>,
62{
63    const DEFAULT_BUILD_SCRIPT: &str = include_str!("resource/buildscript_default.lua");
64
65    let lua = Rc::new(Lua::new());
66
67    let result: Result<(), anyhow::Error> = lua.context(|ctx| {
68        lua::setup_ceres_environ(
69            ctx,
70            run_mode,
71            script_args.into_iter().map(|s| s.into()).collect(),
72        );
73
74        action(ctx)?;
75
76        Ok(())
77    });
78
79    if result.is_err() {
80        handle_lua_result(result);
81        std::process::exit(1);
82    }
83
84    wait_on_evloop(Rc::clone(&lua));
85
86    Ok(())
87}
88
89pub fn run_build_script(
90    run_mode: WarpackRunMode,
91    project_dir: PathBuf,
92    script_args: Vec<&str>,
93) -> Result<(), anyhow::Error> {
94    const DEFAULT_BUILD_SCRIPT: &str = include_str!("resource/buildscript_default.lua");
95
96    let build_script_path = project_dir.join("build.lua");
97
98    let build_script = if build_script_path.is_file() {
99        Some(
100            fs::read_to_string(&build_script_path)
101                .map_err(|cause| ContextError::new("Could not read custom build script", cause))?,
102        )
103    } else {
104        None
105    };
106
107    execute_script(run_mode, script_args, |ctx| {
108        if let Some(build_script) = build_script {
109            ctx.load(&build_script)
110                .set_name("custom build script")
111                .unwrap()
112                .exec()?;
113        }
114
115        ctx.load(DEFAULT_BUILD_SCRIPT)
116            .set_name("buildscript_default.lua")
117            .unwrap()
118            .exec()?;
119
120        Ok(())
121    })
122}