lyrix/src/mods/mod_manager.rs

156 lines
4.0 KiB
Rust

use bevy::{
asset::{AssetLoader, LoadContext, LoadedAsset},
prelude::*,
reflect::TypeUuid,
utils::BoxedFuture,
};
use bevy_console::PrintConsoleLine;
use rhai::Engine;
use serde::Deserialize;
use std::{sync::Arc, sync::RwLock};
use super::modding_api::{register_mod, register_object, register_weapon};
#[derive(Debug, Deserialize, TypeUuid)]
#[uuid = "39cadc56-aa9c-4543-8640-a018b74b5051"]
pub struct Mod {
name: String,
enabled: bool,
}
#[derive(Debug, Deserialize, TypeUuid)]
#[uuid = "39cadc56-aa9c-4543-8640-a018b74b5050"]
pub struct LoadedMod {
name: String,
}
#[derive(Debug, Deserialize, TypeUuid)]
#[uuid = "39cadc56-aa9c-4543-8640-a018b74b5052"]
pub struct ModList {
pub value: i32,
pub vec: Vec<Mod>,
}
#[derive(Default)]
pub struct ModListLoader;
impl AssetLoader for ModListLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), anyhow::Error>> {
Box::pin(async move {
let custom_asset = ron::de::from_bytes::<ModList>(bytes)?;
load_context.set_default_asset(LoadedAsset::new(custom_asset));
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["list"]
}
}
#[derive(Default)]
pub struct ModLoader;
impl AssetLoader for ModLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, Result<(), anyhow::Error>> {
Box::pin(async move {
let custom_asset = LoadedMod {
name: std::str::from_utf8(bytes).unwrap().to_string(),
};
load_context.set_default_asset(LoadedAsset::new(custom_asset));
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["rhai"]
}
}
#[derive(Default)]
pub struct State {
pub handle: Handle<ModList>,
pub mod_handle: Handle<LoadedMod>,
pub loaded: bool,
pub printed: bool,
}
pub struct ModManager;
impl Plugin for ModManager {
fn build(&self, app: &mut AppBuilder) {
app.init_resource::<State>()
.add_asset::<ModList>()
.init_asset_loader::<ModListLoader>()
.add_asset::<LoadedMod>()
.init_asset_loader::<ModLoader>()
.add_startup_system(engine_settings.system())
.add_system(build_mods.system());
}
}
pub struct AddonState {
rebuild_addons: bool,
}
fn build_mods(
mut engine: ResMut<Engine>,
mut addon_state: ResMut<AddonState>,
mut console_line: EventWriter<PrintConsoleLine>,
) {
if !addon_state.rebuild_addons {
return;
}
println!("Rebuilt addons");
let logbook = Arc::new(RwLock::new(Vec::<String>::new()));
// Redirect print/debug output to 'log'
let log = logbook.clone();
engine.on_print(move |s| log.write().unwrap().push(format!("{}", s)));
let log = logbook.clone();
engine.on_debug(move |s, src, pos| {
log.write().unwrap().push(format!(
"DEBUG of {} at {:?}: {}",
src.unwrap_or("unknown"),
pos,
s
))
});
let result = engine.run(include_str!("../../assets/mods/NewSwordMod.lad"));
match result {
Ok(_) => console_line.send(PrintConsoleLine::new("Mod Loaded".to_string())),
Err(error) => console_line.send(PrintConsoleLine::new(error.to_string())),
}
for entry in logbook.read().unwrap().iter() {
console_line.send(PrintConsoleLine::new(entry.to_string()));
}
addon_state.rebuild_addons = false;
}
fn engine_settings(mut commands: Commands) {
let mut engine = Engine::new();
// Configure the engine
engine.set_max_array_size(50).set_max_operations(500);
engine.register_fn("register_mod", register_mod);
engine.register_fn("register_weapon", register_weapon);
engine.register_fn("register_object", register_object);
commands.insert_resource(engine);
commands.insert_resource(AddonState {
rebuild_addons: true,
});
}