Skip to content
Snippets Groups Projects
Verified Commit c9ad3949 authored by Louis's avatar Louis :fire:
Browse files

Update JSON Loader to assets v2

parent cb23278f
No related branches found
No related tags found
No related merge requests found
[package] [package]
name = "micro_games_macros" name = "micro_games_macros"
version = "0.1.1" version = "0.2.0"
edition = "2021" edition = "2021"
authors = ["Louis Capitanchik <contact@louiscap.co>"] authors = ["Louis Capitanchik <contact@louiscap.co>"]
description = "Utility macros to make it easier to build complex systems with Bevy" description = "Utility macros to make it easier to build complex systems with Bevy"
...@@ -28,7 +28,7 @@ anyhow = "1.0.72" ...@@ -28,7 +28,7 @@ anyhow = "1.0.72"
[dev-dependencies.bevy] [dev-dependencies.bevy]
version = "0.11.0" version = "0.12.0"
default-features = false default-features = false
features = [ features = [
"bevy_asset", "bevy_asset",
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
A collection of utility macros for building games A collection of utility macros for building games
**Current Version Support: 0.2.x -> Bevy 0.12**
## Macros ## Macros
For executable examples, visit the rustdoc and/or read the doctests in `src/lib.rs` For executable examples, visit the rustdoc and/or read the doctests in `src/lib.rs`
......
...@@ -24,7 +24,15 @@ fq!(FQDefault => ::core::default::Default); ...@@ -24,7 +24,15 @@ fq!(FQDefault => ::core::default::Default);
fq!(FQSend => ::core::marker::Send); fq!(FQSend => ::core::marker::Send);
fq!(FQSync => ::core::marker::Sync); fq!(FQSync => ::core::marker::Sync);
fq!(FQFrom => ::std::convert::From); fq!(FQFrom => ::std::convert::From);
fq!(FQIOError => ::std::io::Error);
fq!(FQError => ::std::error::Error);
fq!(FQFormatter => ::std::fmt::Formatter);
fq!(FQFormatResult => ::std::fmt::Result);
fq!(FQOption => ::std::option::Option);
fq!(FQResult => ::std::result::Result);
fq!(FQBox => ::std::boxed::Box);
fq!(SerdeJsonError => ::serde_json::Error);
fq!(ImportBevyPrelude => use ::bevy::prelude::*); fq!(ImportBevyPrelude => use ::bevy::prelude::*);
fq!(BevyApp => ::bevy::app::App); fq!(BevyApp => ::bevy::app::App);
...@@ -40,6 +48,7 @@ fq!(BevyTypeUuid => ::bevy::reflect::TypeUuid); ...@@ -40,6 +48,7 @@ fq!(BevyTypeUuid => ::bevy::reflect::TypeUuid);
fq!(BevyDeref => ::bevy::prelude::Deref); fq!(BevyDeref => ::bevy::prelude::Deref);
fq!(BevyDerefMut => ::bevy::prelude::DerefMut); fq!(BevyDerefMut => ::bevy::prelude::DerefMut);
fq!(BevyHandle => ::bevy::asset::Handle); fq!(BevyHandle => ::bevy::asset::Handle);
fq!(BevyAsset => ::bevy::asset::Asset);
fq!(BevyAssets => ::bevy::asset::Assets); fq!(BevyAssets => ::bevy::asset::Assets);
fq!(BevyAssetEvent => ::bevy::asset::AssetEvent); fq!(BevyAssetEvent => ::bevy::asset::AssetEvent);
fq!(BevyAssetLoader => ::bevy::asset::AssetLoader); fq!(BevyAssetLoader => ::bevy::asset::AssetLoader);
...@@ -47,7 +56,9 @@ fq!(BevyBoxedFuture => ::bevy::asset::BoxedFuture); ...@@ -47,7 +56,9 @@ fq!(BevyBoxedFuture => ::bevy::asset::BoxedFuture);
fq!(BevyLoadContext => ::bevy::asset::LoadContext); fq!(BevyLoadContext => ::bevy::asset::LoadContext);
fq!(BevyLoadedAsset => ::bevy::asset::LoadedAsset); fq!(BevyLoadedAsset => ::bevy::asset::LoadedAsset);
fq!(BevyAssetServer => ::bevy::asset::AssetServer); fq!(BevyAssetServer => ::bevy::asset::AssetServer);
fq!(BevyAddAsset => ::bevy::asset::AddAsset); fq!(BevyAddAsset => ::bevy::asset::AssetApp);
fq!(BevyAsyncRead => ::bevy::asset::AsyncReadExt);
fq!(BevyAssetReader => ::bevy::asset::io::Reader);
#[cfg(feature = "kayak")] #[cfg(feature = "kayak")]
fq!(KayakWidget => ::kayak_ui::prelude::Widget); fq!(KayakWidget => ::kayak_ui::prelude::Widget);
...@@ -10,6 +10,7 @@ pub fn json_loader(input: DeriveInput) -> TokenStream { ...@@ -10,6 +10,7 @@ pub fn json_loader(input: DeriveInput) -> TokenStream {
Err(stream) => return stream, Err(stream) => return stream,
}; };
let error_type = define_error_type(&context);
let asset_set = define_loading_type(&context); let asset_set = define_loading_type(&context);
let index_type = define_index_type(&context); let index_type = define_index_type(&context);
let plugin = define_plugin(&context); let plugin = define_plugin(&context);
...@@ -17,6 +18,7 @@ pub fn json_loader(input: DeriveInput) -> TokenStream { ...@@ -17,6 +18,7 @@ pub fn json_loader(input: DeriveInput) -> TokenStream {
let load_handler = define_load_handler(&context); let load_handler = define_load_handler(&context);
quote! { quote! {
#error_type
#asset_set #asset_set
#index_type #index_type
#loader #loader
...@@ -56,57 +58,105 @@ pub fn define_index_type( ...@@ -56,57 +58,105 @@ pub fn define_index_type(
}: &IdentContext, }: &IdentContext,
) -> TokenStream { ) -> TokenStream {
quote! { quote! {
#[derive(#FQDebug, #BevyTypePath, #BevyTypeUuid, #BevyDeref, #BevyDerefMut)] #[derive(#FQDebug, #BevyTypePath, #BevyTypeUuid, #BevyDeref, #BevyDerefMut, #BevyAsset)]
#[uuid = #uuid] #[uuid = #uuid]
#vis struct #index_name(pub #FQHashMap<String, #BevyHandle<#asset_name>>); #vis struct #index_name(pub #FQHashMap<String, #BevyHandle<#asset_name>>);
} }
} }
pub fn define_error_type(IdentContext { error_name, .. }: &IdentContext) -> TokenStream {
quote! {
#[derive(#FQDebug)]
pub enum #error_name {
Io(#FQIOError),
Json(#SerdeJsonError)
}
impl #FQDisplay for #error_name {
fn fmt(&self, f: &mut #FQFormatter<'_>) -> #FQFormatResult {
match self {
#error_name::Io(err) => err.fmt(f),
#error_name::Json(err) => err.fmt(f),
}
}
}
impl #FQError for #error_name {
fn source(&self) -> #FQOption<&(dyn #FQError + 'static)> {
match self {
#error_name::Io(err) => Some(err),
#error_name::Json(err) => Some(err),
}
}
}
impl #FQFrom<#FQIOError> for #error_name {
fn from(value: #FQIOError) -> #error_name {
#error_name::Io(value)
}
}
impl #FQFrom<#SerdeJsonError> for #error_name {
fn from(value: #SerdeJsonError) -> #error_name {
#error_name::Json(value)
}
}
}
}
pub fn define_loader( pub fn define_loader(
IdentContext { IdentContext {
vis, vis,
loader_name, loader_name,
index_name, index_name,
set_name, set_name,
error_name,
id_field, id_field,
extension, extension,
.. ..
}: &IdentContext, }: &IdentContext,
) -> TokenStream { ) -> TokenStream {
quote! { quote! {
#[derive(#FQDefault)]
#vis struct #loader_name; #vis struct #loader_name;
impl #BevyAssetLoader for #loader_name { impl #BevyAssetLoader for #loader_name {
type Asset = #index_name;
type Settings = ();
type Error = #error_name;
fn load<'a>( fn load<'a>(
&'a self, &'a self,
bytes: &'a [u8], mut reader: &'a mut #BevyAssetReader,
_settings: &'a Self::Settings,
load_context: &'a mut #BevyLoadContext, load_context: &'a mut #BevyLoadContext,
) -> #BevyBoxedFuture<'a, ::anyhow::Result<()>> { ) -> #BevyBoxedFuture<'a, #FQResult<Self::Asset, Self::Error>> {
Box::pin(async { #FQBox::pin(async move {
let data: #set_name = ::serde_json::from_slice(bytes)?; let mut bytes = #FQVec::new();
#BevyAsyncRead::read_to_end(&mut reader, &mut bytes).await?;
let data: #set_name = ::serde_json::from_slice(bytes.as_slice())?;
let mut asset_map = #FQHashMap::new(); let mut asset_map = #FQHashMap::new();
match data { match data {
#set_name::One(single_asset) => { #set_name::One(single_asset) => {
let asset_id = format!("{}", &single_asset.#id_field); let asset_id = format!("{}", &single_asset.#id_field);
let handle = load_context.set_labeled_asset( let handle = load_context.add_labeled_asset(
asset_id.as_str(), asset_id.clone(),
#BevyLoadedAsset::new(single_asset), single_asset,
); );
asset_map.insert(asset_id, handle); asset_map.insert(asset_id, handle);
} }
#set_name::Many(asset_list) => { #set_name::Many(asset_list) => {
for single_asset in asset_list.into_iter() { for single_asset in asset_list.into_iter() {
let asset_id = format!("{}", &single_asset.#id_field); let asset_id = format!("{}", &single_asset.#id_field);
let handle = load_context.set_labeled_asset( let handle = load_context.add_labeled_asset(
asset_id.as_str(), asset_id.clone(),
#BevyLoadedAsset::new(single_asset), single_asset,
); );
asset_map.insert(asset_id, handle); asset_map.insert(asset_id, handle);
} }
} }
} }
load_context.set_default_asset(#BevyLoadedAsset::new(#index_name(asset_map))); Ok(#index_name(asset_map))
Ok(())
}) })
} }
...@@ -132,9 +182,9 @@ pub fn define_plugin( ...@@ -132,9 +182,9 @@ pub fn define_plugin(
#vis struct #plugin_name; #vis struct #plugin_name;
impl #BevyPlugin for #plugin_name { impl #BevyPlugin for #plugin_name {
fn build(&self, app: &mut #BevyApp) { fn build(&self, app: &mut #BevyApp) {
#BevyAddAsset::add_asset::<#asset_name>(app); #BevyAddAsset::init_asset::<#asset_name>(app);
#BevyAddAsset::add_asset::<#index_name>(app); #BevyAddAsset::init_asset::<#index_name>(app);
#BevyAddAsset::add_asset_loader(app, #loader_name); #BevyAddAsset::init_asset_loader::<#loader_name>(app);
app.add_systems(#BevyUpdate, #handler_name); app.add_systems(#BevyUpdate, #handler_name);
} }
} }
...@@ -163,21 +213,22 @@ pub fn define_load_handler( ...@@ -163,21 +213,22 @@ pub fn define_load_handler(
for event in events.iter() { for event in events.iter() {
match event { match event {
#BevyAssetEvent::Created { handle } | #BevyAssetEvent::Modified { handle } => { #BevyAssetEvent::LoadedWithDependencies { id } | #BevyAssetEvent::Added { id } | #BevyAssetEvent::Modified { id } => {
let handle = #BevyHandle::Weak(*id);
if let Some(asset_container) = asset_data.get(handle) { if let Some(asset_container) = asset_data.get(handle) {
for (id, handle) in asset_container.iter() { for (id, handle) in asset_container.iter() {
asset_storage.#storage_asset_name.insert(id.clone(), handle.clone()); asset_storage.#storage_asset_name.insert(id.clone(), handle.clone());
} }
} }
} }
#BevyAssetEvent::Removed { handle } => { #BevyAssetEvent::Removed { id } => {
asset_storage.#storage_index_name.iter().for_each(|(id, stored)| { asset_storage.#storage_index_name.iter().for_each(|(key, stored)| {
if stored == handle { if stored.id() == *id {
if let Some(asset_container) = asset_data.get(stored) { if let Some(asset_container) = asset_data.get(stored) {
for (id, _) in asset_container.iter() { for (key, _) in asset_container.iter() {
removed_assets.push(id.clone()); removed_assets.push(key.clone());
} }
removed_containers.push(id.clone()); removed_containers.push(key.clone());
} }
} }
}); });
......
...@@ -13,6 +13,7 @@ pub struct IdentContext { ...@@ -13,6 +13,7 @@ pub struct IdentContext {
pub plugin_name: Ident, pub plugin_name: Ident,
pub loader_name: Ident, pub loader_name: Ident,
pub handler_name: Ident, pub handler_name: Ident,
pub error_name: Ident,
// -- Property names // -- Property names
pub id_field: Ident, pub id_field: Ident,
pub storage_type: TokenStream, pub storage_type: TokenStream,
...@@ -105,6 +106,7 @@ impl IdentContext { ...@@ -105,6 +106,7 @@ impl IdentContext {
loader_name: ident_suffix(&ident, "Loader"), loader_name: ident_suffix(&ident, "Loader"),
set_name: ident_suffix(&ident, "Set"), set_name: ident_suffix(&ident, "Set"),
plugin_name: ident_suffix(&ident, "Plugin"), plugin_name: ident_suffix(&ident, "Plugin"),
error_name: ident_suffix(&ident, "Error"),
handler_name: ident_suffix(&snake_case_ident(&ident), "_load_handler"), handler_name: ident_suffix(&snake_case_ident(&ident), "_load_handler"),
asset_name: ident.clone(), asset_name: ident.clone(),
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
//! to the generated asset system //! to the generated asset system
//! //!
//! ```rust //! ```rust
//! use bevy::prelude::{App, DefaultPlugins, Image, Plugin, Res, ResMut, Resource, Assets, TextureAtlas}; //! use bevy::prelude::{App, DefaultPlugins, Image, Plugin, Res, ResMut, Resource, Assets, Asset, TextureAtlas};
//! use bevy::reflect::{TypePath, TypeUuid}; //! use bevy::reflect::{TypePath, TypeUuid};
//! use micro_games_macros::{asset_system, JsonLoader}; //! use micro_games_macros::{asset_system, JsonLoader};
//! use serde::{Deserialize, Serialize}; //! use serde::{Deserialize, Serialize};
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
//! some_index_of_resources: MyCoolResourceIndex, //! some_index_of_resources: MyCoolResourceIndex,
//! } //! }
//! //!
//! #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize)] //! #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize, Asset)]
//! #[loader(extension = "mcr", uuid = "00000000-0000-0000-0000-000000000000", //! #[loader(extension = "mcr", uuid = "00000000-0000-0000-0000-000000000000",
//! asset_name = some_resource, index_name = some_index_of_resources)] //! asset_name = some_resource, index_name = some_index_of_resources)]
//! #[uuid = "10000000-0000-0000-0000-000000000001"] //! #[uuid = "10000000-0000-0000-0000-000000000001"]
...@@ -128,7 +128,7 @@ pub(crate) mod std_traits; ...@@ -128,7 +128,7 @@ pub(crate) mod std_traits;
/// ///
/// ```rust /// ```rust
/// # use std::collections::HashMap; /// # use std::collections::HashMap;
/// # use bevy::asset::Handle; /// # use bevy::asset::{Handle, Asset};
/// # use bevy::prelude::Resource; /// # use bevy::prelude::Resource;
/// # use bevy::reflect::{TypePath, TypeUuid}; /// # use bevy::reflect::{TypePath, TypeUuid};
/// # use serde::{Deserialize, Serialize}; /// # use serde::{Deserialize, Serialize};
...@@ -140,7 +140,7 @@ pub(crate) mod std_traits; ...@@ -140,7 +140,7 @@ pub(crate) mod std_traits;
/// simple_asset_index: HashMap<String, Handle<SimpleAssetIndex>>, /// simple_asset_index: HashMap<String, Handle<SimpleAssetIndex>>,
/// } /// }
/// ///
/// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize)] /// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize, Asset)]
/// #[loader(extension = "satt", uuid = "00000000-0000-0000-0000-000000000000")] /// #[loader(extension = "satt", uuid = "00000000-0000-0000-0000-000000000000")]
/// #[uuid = "00000000-0000-0000-0000-000000000001"] /// #[uuid = "00000000-0000-0000-0000-000000000001"]
/// pub struct SimpleAsset { /// pub struct SimpleAsset {
...@@ -159,13 +159,13 @@ pub(crate) mod std_traits; ...@@ -159,13 +159,13 @@ pub(crate) mod std_traits;
/// ///
/// ```rust /// ```rust
/// # use std::collections::HashMap; /// # use std::collections::HashMap;
/// # use bevy::asset::Handle; /// # use bevy::asset::{Handle, Asset};
/// # use bevy::prelude::Resource; /// # use bevy::prelude::Resource;
/// # use bevy::reflect::{TypePath, TypeUuid}; /// # use bevy::reflect::{TypePath, TypeUuid};
/// # use serde::{Deserialize, Serialize}; /// # use serde::{Deserialize, Serialize};
/// # use micro_games_macros::JsonLoader; /// # use micro_games_macros::JsonLoader;
/// ///
/// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize)] /// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize, Asset)]
/// #[loader( /// #[loader(
/// extension = "asset.json", uuid = "00000000-0000-0000-0000-000000000000", /// extension = "asset.json", uuid = "00000000-0000-0000-0000-000000000000",
/// storage = inner_module::SimpleAssetLocator, /// storage = inner_module::SimpleAssetLocator,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment