use bevy::asset::io::Reader;
use bevy::asset::{Asset, AssetApp, AssetLoader, LoadContext};
use bevy::platform::collections::HashMap;
use bevy::prelude::*;
use symbios::System;
use crate::materials::MaterialSettings;
#[derive(Asset, TypePath)]
pub struct LSystemSource(pub System);
#[derive(Asset, TypePath)]
pub struct MaterialSettingsSource(pub HashMap<u16, MaterialSettings>);
#[derive(Debug)]
pub enum LSystemLoaderError {
Io(std::io::Error),
Utf8(std::string::FromUtf8Error),
Parse(symbios::system::SystemError),
}
impl std::fmt::Display for LSystemLoaderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(e) => write!(f, "I/O error reading .lsys: {e}"),
Self::Utf8(e) => write!(f, "Invalid UTF-8 in .lsys: {e}"),
Self::Parse(e) => write!(f, "L-System parse error: {e:?}"),
}
}
}
impl std::error::Error for LSystemLoaderError {}
impl From<std::io::Error> for LSystemLoaderError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<std::string::FromUtf8Error> for LSystemLoaderError {
fn from(e: std::string::FromUtf8Error) -> Self {
Self::Utf8(e)
}
}
impl From<symbios::system::SystemError> for LSystemLoaderError {
fn from(e: symbios::system::SystemError) -> Self {
Self::Parse(e)
}
}
#[derive(Debug)]
pub enum MaterialSettingsLoaderError {
Io(std::io::Error),
Json(serde_json::Error),
}
impl std::fmt::Display for MaterialSettingsLoaderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(e) => write!(f, "I/O error reading material palette: {e}"),
Self::Json(e) => write!(f, "JSON parse error: {e}"),
}
}
}
impl std::error::Error for MaterialSettingsLoaderError {}
impl From<std::io::Error> for MaterialSettingsLoaderError {
fn from(e: std::io::Error) -> Self {
Self::Io(e)
}
}
impl From<serde_json::Error> for MaterialSettingsLoaderError {
fn from(e: serde_json::Error) -> Self {
Self::Json(e)
}
}
#[derive(Default, TypePath)]
pub struct LSystemAssetLoader;
impl AssetLoader for LSystemAssetLoader {
type Asset = LSystemSource;
type Settings = ();
type Error = LSystemLoaderError;
async fn load(
&self,
reader: &mut dyn Reader,
_settings: &Self::Settings,
_load_context: &mut LoadContext<'_>,
) -> Result<LSystemSource, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
let source = String::from_utf8(bytes)?;
let system = parse_lsys_source(&source)?;
Ok(LSystemSource(system))
}
fn extensions(&self) -> &[&str] {
&["lsys"]
}
}
#[derive(Default, TypePath)]
pub struct MaterialSettingsAssetLoader;
impl AssetLoader for MaterialSettingsAssetLoader {
type Asset = MaterialSettingsSource;
type Settings = ();
type Error = MaterialSettingsLoaderError;
async fn load(
&self,
reader: &mut dyn Reader,
_settings: &Self::Settings,
_load_context: &mut LoadContext<'_>,
) -> Result<MaterialSettingsSource, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
let map = parse_material_settings(&bytes)?;
Ok(MaterialSettingsSource(map))
}
fn extensions(&self) -> &[&str] {
&["matpalette.json"]
}
}
pub fn parse_lsys_source(src: &str) -> Result<System, symbios::system::SystemError> {
System::from_source(src)
}
pub fn parse_material_settings(
bytes: &[u8],
) -> Result<HashMap<u16, MaterialSettings>, serde_json::Error> {
serde_json::from_slice(bytes)
}
pub struct LSystemAssetPlugin;
impl Plugin for LSystemAssetPlugin {
fn build(&self, app: &mut App) {
app.init_asset::<LSystemSource>()
.init_asset::<MaterialSettingsSource>()
.init_asset_loader::<LSystemAssetLoader>()
.init_asset_loader::<MaterialSettingsAssetLoader>();
}
}