Skip to content

Commit

Permalink
Added fragments to resources.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Apr 9, 2024
1 parent c2b4c2e commit 1530f25
Show file tree
Hide file tree
Showing 11 changed files with 405 additions and 187 deletions.
2 changes: 1 addition & 1 deletion assets/pbr.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
{
"name": "color",
"data_type": "Texture2D",
"value": "patterned_brick_floor_02_diff_2k.png"
"value": "Revolver.glb#Revolver_Base_color"
}
]
}
8 changes: 7 additions & 1 deletion resource_management/src/asset/asset_handler.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use crate::{GenericResourceResponse, GenericResourceSerialization, StorageBackend};
use crate::{Description, GenericResourceSerialization, Resource, StorageBackend};

use super::{asset_manager::AssetManager, AssetResolver};

/// An asset handler is responsible for loading assets of a certain type from a url.
pub trait AssetHandler {
fn can_handle(&self, r#type: &str) -> bool {
false
}

/// Load an asset from a url.
/// # Arguments
/// * `id` - The id of the asset.
Expand All @@ -18,4 +22,6 @@ pub trait AssetHandler {
/// Returns Some(...) if the asset was managed by this handler, None otherwise.
/// Returns Some(Ok(...)) if the asset was loaded successfully, Some(Err(...)) otherwise.
fn load<'a>(&'a self, asset_manager: &'a AssetManager, asset_resolver: &'a dyn AssetResolver, storage_backend: &'a dyn StorageBackend, url: &'a str, json: Option<&'a json::JsonValue>) -> utils::BoxedFuture<'a, Result<Option<GenericResourceSerialization>, String>>;

fn produce<'a>(&'a self, description: &'a dyn crate::Description, data: &'a [u8]) -> utils::BoxedFuture<'a, Result<(Box<dyn Resource>, Box<[u8]>), String>>;
}
92 changes: 58 additions & 34 deletions resource_management/src/asset/asset_manager.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
use smol::{io::AsyncReadExt, stream::StreamExt};
use std::ops::Deref;

use crate::{asset::{read_asset_from_source, AssetResolver}, DbStorageBackend, Model, Resource, Solver, StorageBackend, TypedResource, TypedResourceModel};
use crate::{asset::{read_asset_from_source, AssetResolver}, DbStorageBackend, Description, Model, Resource, Solver, StorageBackend, TypedResource, TypedResourceModel};

use super::asset_handler::AssetHandler;

struct MyAssetResolver {}

impl AssetResolver for MyAssetResolver {
fn resolve<'a>(&'a self, url: &'a str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Option<(Vec<u8>, String)>> + Send + 'a>> {
Box::pin(async move {
read_asset_from_source(url, Some(&assets_path())).await.ok()
})
}
}

pub struct AssetManager {
asset_handlers: Vec<Box<dyn AssetHandler>>,
storage_backend: DbStorageBackend,
storage_backend: Box<dyn StorageBackend>,
}

/// Enumeration of the possible messages that can be returned when loading an asset.
Expand All @@ -33,9 +43,13 @@ impl AssetManager {

// let mut memory_only = args.find(|arg| arg == "--ResourceManager.memory_only").is_some();

Self::new_with_storage_backend(DbStorageBackend::new(&resolve_internal_path(std::path::Path::new("assets.db"))))
}

pub fn new_with_storage_backend<SB: StorageBackend>(storage_backend: SB) -> AssetManager {
AssetManager {
asset_handlers: Vec::new(),
storage_backend: DbStorageBackend::new(&resolve_internal_path(std::path::Path::new("assets.db"))),
storage_backend: Box::new(storage_backend),
}
}

Expand All @@ -45,21 +59,11 @@ impl AssetManager {

/// Load a source asset from a JSON asset description.
pub async fn load(&self, id: &str) -> Result<(), LoadMessages> {
struct MyAssetResolver {}

impl AssetResolver for MyAssetResolver {
fn resolve<'a>(&'a self, url: &'a str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Option<(Vec<u8>, String)>> + Send + 'a>> {
Box::pin(async move {
read_asset_from_source(url, Some(&assets_path())).await.ok()
})
}
}

let asset_resolver = MyAssetResolver {};

let storage_backend = &self.storage_backend;

let asset_handler_loads = self.asset_handlers.iter().map(|asset_handler| asset_handler.load(self, &asset_resolver, storage_backend, id, None));
let asset_handler_loads = self.asset_handlers.iter().map(|asset_handler| asset_handler.load(self, &asset_resolver, storage_backend.deref(), id, None));

let load_results = futures::future::join_all(asset_handler_loads).await;

Expand All @@ -74,25 +78,15 @@ impl AssetManager {
}

pub fn get_storage_backend(&self) -> &dyn StorageBackend {
&self.storage_backend
self.storage_backend.deref()
}

pub async fn load_typed_resource<'a, T: Resource + Model + for <'de> serde::Deserialize<'de>>(&self, id: &str) -> Result<TypedResource<T>, LoadMessages> where TypedResourceModel<T>: Solver<'a, TypedResource<T>> {
struct MyAssetResolver {}

impl AssetResolver for MyAssetResolver {
fn resolve<'a>(&'a self, url: &'a str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Option<(Vec<u8>, String)>> + Send + 'a>> {
Box::pin(async move {
read_asset_from_source(url, Some(&assets_path())).await.ok()
})
}
}

pub async fn load_typed_resource<'a, T: Resource + Model + Clone + for <'de> serde::Deserialize<'de>>(&self, id: &str) -> Result<TypedResource<T>, LoadMessages> where TypedResourceModel<T>: Solver<'a, TypedResource<T>> {
let asset_resolver = MyAssetResolver {};

let storage_backend = &self.storage_backend;

let asset_handler_loads = self.asset_handlers.iter().map(|asset_handler| asset_handler.load(self, &asset_resolver, storage_backend, id, None));
let asset_handler_loads = self.asset_handlers.iter().map(|asset_handler| asset_handler.load(self, &asset_resolver, storage_backend.deref(), id, None));

let load_results = futures::future::join_all(asset_handler_loads).await;

Expand All @@ -106,13 +100,37 @@ impl AssetManager {
let meta_resource = load_results.iter().find(|load_result| { load_result.is_ok() }).ok_or(LoadMessages::NoAsset)?.clone().unwrap().unwrap();

let resource: TypedResourceModel<T> = meta_resource.try_into().or(Err(LoadMessages::IO))?;
let resource = resource.solve(storage_backend).or_else(|error| {
let resource = resource.solve(storage_backend.deref()).or_else(|_| {
log::error!("Failed to solve resource {}", id);
Err(LoadMessages::IO)
})?;

Ok(resource.into())
}

pub async fn produce<'a, D: Description, R: Resource + Clone + serde::Serialize>(&self, id: &str, resource_type: &str, description: &D, data: &[u8]) -> TypedResource<R> {
let asset_handler = self.asset_handlers.iter().find(|asset_handler| asset_handler.can_handle(resource_type)).expect("No asset handler found for class");

let (resource, buffer) = match asset_handler.produce(description, data).await {
Ok(x) => x,
Err(error) => {
log::error!("Failed to produce resource: {}", error);
panic!("Failed to produce resource");
}
};

let resource = resource.into_any();

if let Ok(resource) = resource.downcast::<R>() {
let resource = TypedResource::new(id, 0, *resource);

self.storage_backend.store(&resource.clone().into(), &buffer).await.unwrap();

resource
} else {
panic!("Failed to downcast resource");
}
}
}

fn resolve_internal_path(path: &std::path::Path) -> std::path::PathBuf {
Expand Down Expand Up @@ -140,9 +158,9 @@ mod tests {
use polodb_core::bson;
use smol::future::FutureExt;

use crate::{GenericResourceResponse, GenericResourceSerialization};
use crate::GenericResourceSerialization;

use super::*;
use super::*;

struct TestAssetHandler {

Expand All @@ -154,6 +172,8 @@ use super::*;
}
}

struct TestDescription {}

impl AssetHandler for TestAssetHandler {
fn load<'a>(&'a self, _: &'a AssetManager, _: &'a dyn AssetResolver, _ : &'a dyn StorageBackend, id: &'a str, _: Option<&'a json::JsonValue>) -> utils::BoxedFuture<'a, Result<Option<GenericResourceSerialization>, String>> {
let res = if id == "example" {
Expand All @@ -164,6 +184,10 @@ use super::*;

async move { res }.boxed()
}

fn produce<'a>(&'a self, _: &'a dyn crate::Description, _: &'a [u8]) -> utils::BoxedFuture<'a, Result<(Box<dyn Resource>, Box<[u8]>), String>> {
unimplemented!()
}
}

#[test]
Expand All @@ -189,7 +213,7 @@ use super::*;

asset_manager.add_asset_handler(test_asset_handler);

let json = json::parse(r#"{"url": "http://example.com"}"#).unwrap();
let _ = json::parse(r#"{"url": "http://example.com"}"#).unwrap();

// assert_eq!(smol::block_on(asset_manager.load("example", &json)), Ok(()));
}
Expand All @@ -199,7 +223,7 @@ use super::*;
fn test_load_no_asset_handler() {
let asset_manager = AssetManager::new();

let json = json::parse(r#"{"url": "http://example.com"}"#).unwrap();
let _ = json::parse(r#"{"url": "http://example.com"}"#).unwrap();

// assert_eq!(smol::block_on(asset_manager.load("example", &json)), Err(LoadMessages::NoAssetHandler));
}
Expand All @@ -209,7 +233,7 @@ use super::*;
fn test_load_no_asset_url() {
let asset_manager = AssetManager::new();

let json = json::parse(r#"{}"#).unwrap();
let _ = json::parse(r#"{}"#).unwrap();

// assert_eq!(smol::block_on(asset_manager.load("example", &json)), Err(LoadMessages::NoURL));
}
Expand Down
14 changes: 12 additions & 2 deletions resource_management/src/asset/audio_asset_handler.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{types::{Audio, BitDepths}, GenericResourceResponse, GenericResourceSerialization, StorageBackend};
use crate::{types::{Audio, BitDepths}, Description, GenericResourceResponse, GenericResourceSerialization, Resource, StorageBackend};

use super::{asset_handler::AssetHandler, asset_manager::AssetManager, AssetResolver};

Expand Down Expand Up @@ -96,11 +96,21 @@ impl AssetHandler for AudioAssetHandler {

let resource = GenericResourceSerialization::new(url, audio_resource);

storage_backend.store(resource.clone(), data.into()).await.map_err(|_| format!("Failed to store resource"))?;
storage_backend.store(&resource, data.into()).await.map_err(|_| format!("Failed to store resource"))?;

Ok(Some(resource))
})
}

fn produce<'a>(&'a self, _: &'a dyn Description, _: &'a [u8]) -> utils::BoxedFuture<'a, Result<(Box<dyn Resource>, Box<[u8]>), String>> {
Box::pin(async move {
Err("Not implemented".to_string())
})
}
}

struct AudioDescription {

}

#[cfg(test)]
Expand Down
Loading

0 comments on commit 1530f25

Please sign in to comment.