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]
name = "micro_games_macros"
version = "0.1.1"
version = "0.2.0"
edition = "2021"
authors = ["Louis Capitanchik <contact@louiscap.co>"]
description = "Utility macros to make it easier to build complex systems with Bevy"
......@@ -28,7 +28,7 @@ anyhow = "1.0.72"
[dev-dependencies.bevy]
version = "0.11.0"
version = "0.12.0"
default-features = false
features = [
"bevy_asset",
......
......@@ -5,6 +5,8 @@
A collection of utility macros for building games
**Current Version Support: 0.2.x -> Bevy 0.12**
## Macros
For executable examples, visit the rustdoc and/or read the doctests in `src/lib.rs`
......
......@@ -24,7 +24,15 @@ fq!(FQDefault => ::core::default::Default);
fq!(FQSend => ::core::marker::Send);
fq!(FQSync => ::core::marker::Sync);
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!(BevyApp => ::bevy::app::App);
......@@ -40,6 +48,7 @@ fq!(BevyTypeUuid => ::bevy::reflect::TypeUuid);
fq!(BevyDeref => ::bevy::prelude::Deref);
fq!(BevyDerefMut => ::bevy::prelude::DerefMut);
fq!(BevyHandle => ::bevy::asset::Handle);
fq!(BevyAsset => ::bevy::asset::Asset);
fq!(BevyAssets => ::bevy::asset::Assets);
fq!(BevyAssetEvent => ::bevy::asset::AssetEvent);
fq!(BevyAssetLoader => ::bevy::asset::AssetLoader);
......@@ -47,7 +56,9 @@ fq!(BevyBoxedFuture => ::bevy::asset::BoxedFuture);
fq!(BevyLoadContext => ::bevy::asset::LoadContext);
fq!(BevyLoadedAsset => ::bevy::asset::LoadedAsset);
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")]
fq!(KayakWidget => ::kayak_ui::prelude::Widget);
......@@ -10,6 +10,7 @@ pub fn json_loader(input: DeriveInput) -> TokenStream {
Err(stream) => return stream,
};
let error_type = define_error_type(&context);
let asset_set = define_loading_type(&context);
let index_type = define_index_type(&context);
let plugin = define_plugin(&context);
......@@ -17,6 +18,7 @@ pub fn json_loader(input: DeriveInput) -> TokenStream {
let load_handler = define_load_handler(&context);
quote! {
#error_type
#asset_set
#index_type
#loader
......@@ -56,57 +58,105 @@ pub fn define_index_type(
}: &IdentContext,
) -> TokenStream {
quote! {
#[derive(#FQDebug, #BevyTypePath, #BevyTypeUuid, #BevyDeref, #BevyDerefMut)]
#[derive(#FQDebug, #BevyTypePath, #BevyTypeUuid, #BevyDeref, #BevyDerefMut, #BevyAsset)]
#[uuid = #uuid]
#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(
IdentContext {
vis,
loader_name,
index_name,
set_name,
error_name,
id_field,
extension,
..
}: &IdentContext,
) -> TokenStream {
quote! {
#[derive(#FQDefault)]
#vis struct #loader_name;
impl #BevyAssetLoader for #loader_name {
type Asset = #index_name;
type Settings = ();
type Error = #error_name;
fn load<'a>(
&'a self,
bytes: &'a [u8],
mut reader: &'a mut #BevyAssetReader,
_settings: &'a Self::Settings,
load_context: &'a mut #BevyLoadContext,
) -> #BevyBoxedFuture<'a, ::anyhow::Result<()>> {
Box::pin(async {
let data: #set_name = ::serde_json::from_slice(bytes)?;
) -> #BevyBoxedFuture<'a, #FQResult<Self::Asset, Self::Error>> {
#FQBox::pin(async move {
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();
match data {
#set_name::One(single_asset) => {
let asset_id = format!("{}", &single_asset.#id_field);
let handle = load_context.set_labeled_asset(
asset_id.as_str(),
#BevyLoadedAsset::new(single_asset),
let handle = load_context.add_labeled_asset(
asset_id.clone(),
single_asset,
);
asset_map.insert(asset_id, handle);
}
#set_name::Many(asset_list) => {
for single_asset in asset_list.into_iter() {
let asset_id = format!("{}", &single_asset.#id_field);
let handle = load_context.set_labeled_asset(
asset_id.as_str(),
#BevyLoadedAsset::new(single_asset),
let handle = load_context.add_labeled_asset(
asset_id.clone(),
single_asset,
);
asset_map.insert(asset_id, handle);
}
}
}
load_context.set_default_asset(#BevyLoadedAsset::new(#index_name(asset_map)));
Ok(())
Ok(#index_name(asset_map))
})
}
......@@ -132,9 +182,9 @@ pub fn define_plugin(
#vis struct #plugin_name;
impl #BevyPlugin for #plugin_name {
fn build(&self, app: &mut #BevyApp) {
#BevyAddAsset::add_asset::<#asset_name>(app);
#BevyAddAsset::add_asset::<#index_name>(app);
#BevyAddAsset::add_asset_loader(app, #loader_name);
#BevyAddAsset::init_asset::<#asset_name>(app);
#BevyAddAsset::init_asset::<#index_name>(app);
#BevyAddAsset::init_asset_loader::<#loader_name>(app);
app.add_systems(#BevyUpdate, #handler_name);
}
}
......@@ -163,21 +213,22 @@ pub fn define_load_handler(
for event in events.iter() {
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) {
for (id, handle) in asset_container.iter() {
asset_storage.#storage_asset_name.insert(id.clone(), handle.clone());
}
}
}
#BevyAssetEvent::Removed { handle } => {
asset_storage.#storage_index_name.iter().for_each(|(id, stored)| {
if stored == handle {
#BevyAssetEvent::Removed { id } => {
asset_storage.#storage_index_name.iter().for_each(|(key, stored)| {
if stored.id() == *id {
if let Some(asset_container) = asset_data.get(stored) {
for (id, _) in asset_container.iter() {
removed_assets.push(id.clone());
for (key, _) in asset_container.iter() {
removed_assets.push(key.clone());
}
removed_containers.push(id.clone());
removed_containers.push(key.clone());
}
}
});
......
......@@ -13,6 +13,7 @@ pub struct IdentContext {
pub plugin_name: Ident,
pub loader_name: Ident,
pub handler_name: Ident,
pub error_name: Ident,
// -- Property names
pub id_field: Ident,
pub storage_type: TokenStream,
......@@ -105,6 +106,7 @@ impl IdentContext {
loader_name: ident_suffix(&ident, "Loader"),
set_name: ident_suffix(&ident, "Set"),
plugin_name: ident_suffix(&ident, "Plugin"),
error_name: ident_suffix(&ident, "Error"),
handler_name: ident_suffix(&snake_case_ident(&ident), "_load_handler"),
asset_name: ident.clone(),
......
......@@ -5,7 +5,7 @@
//! to the generated asset system
//!
//! ```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 micro_games_macros::{asset_system, JsonLoader};
//! use serde::{Deserialize, Serialize};
......@@ -38,7 +38,7 @@
//! 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",
//! asset_name = some_resource, index_name = some_index_of_resources)]
//! #[uuid = "10000000-0000-0000-0000-000000000001"]
......@@ -128,7 +128,7 @@ pub(crate) mod std_traits;
///
/// ```rust
/// # use std::collections::HashMap;
/// # use bevy::asset::Handle;
/// # use bevy::asset::{Handle, Asset};
/// # use bevy::prelude::Resource;
/// # use bevy::reflect::{TypePath, TypeUuid};
/// # use serde::{Deserialize, Serialize};
......@@ -140,7 +140,7 @@ pub(crate) mod std_traits;
/// 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")]
/// #[uuid = "00000000-0000-0000-0000-000000000001"]
/// pub struct SimpleAsset {
......@@ -159,13 +159,13 @@ pub(crate) mod std_traits;
///
/// ```rust
/// # use std::collections::HashMap;
/// # use bevy::asset::Handle;
/// # use bevy::asset::{Handle, Asset};
/// # use bevy::prelude::Resource;
/// # use bevy::reflect::{TypePath, TypeUuid};
/// # use serde::{Deserialize, Serialize};
/// # use micro_games_macros::JsonLoader;
///
/// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize)]
/// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize, Asset)]
/// #[loader(
/// extension = "asset.json", uuid = "00000000-0000-0000-0000-000000000000",
/// 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