use bevy::app::{App, Plugin};
use bevy::asset::{
AddAsset, AssetLoader, AssetServer, Assets, BoxedFuture, Error, LoadContext, LoadedAsset,
};
use bevy::ecs::system::SystemParam;
use bevy::prelude::Res;
use serde::Deserialize;
use crate::quest_log::QuestLocator;
use crate::{Quest, QuestLog};
#[derive(Deserialize)]
struct QuestFile {
quests: Vec<Quest>,
}
pub struct QuestFileLoader;
impl AssetLoader for QuestFileLoader {
fn load<'a>(
&'a self,
bytes: &'a [u8],
load_context: &'a mut LoadContext,
) -> BoxedFuture<'a, anyhow::Result<(), Error>> {
Box::pin(async move {
let bytes_as_str = String::from_utf8(bytes.to_vec())?;
let value: QuestFile =
toml::from_str(&bytes_as_str).map_err(|e| Error::msg(format!("{}", e)))?;
for quest in value.quests {
let id = quest.id.clone();
load_context.set_labeled_asset(id.as_str(), LoadedAsset::new(quest));
}
Ok(())
})
}
fn extensions(&self) -> &[&str] {
&["quest"]
}
}
pub struct MicroQuestPlugin;
impl Plugin for MicroQuestPlugin {
fn build(&self, app: &mut App) {
app.add_asset::<Quest>()
.add_asset_loader(QuestFileLoader)
.init_resource::<QuestLog>();
}
}
#[derive(SystemParam)]
pub struct AssetServerQuestLocator<'w> {
pub assets: Res<'w, AssetServer>,
pub quests: Res<'w, Assets<Quest>>,
}
impl<'w> QuestLocator for AssetServerQuestLocator<'w> {
fn get_quest(&self, id: impl ToString) -> Option<&Quest> {
let base_id = id.to_string();
let mut parts = base_id.split('#');
let root = parts.next();
let inner_id = parts.next();
root.map(|root| {
let name = if let Some(inner_id) = inner_id {
format!("{}.quest#{}", root, inner_id)
} else {
format!("{}.quest", root)
};
self.assets.load(name)
})
.and_then(|handle| self.quests.get(&handle))
}
}