12_custom_protocol_advanced/
12_custom_protocol_advanced.rs1use anput::world::World;
2use keket::{
3 database::{
4 AssetDatabase,
5 handle::{AssetDependency, AssetHandle},
6 path::AssetPathStatic,
7 },
8 fetch::{AssetAwaitsResolution, AssetBytesAreReadyToProcess, file::FileAssetFetch},
9 protocol::AssetProtocol,
10};
11use serde::Deserialize;
12use std::error::Error;
13
14fn main() -> Result<(), Box<dyn Error>> {
15 let mut database = AssetDatabase::default()
16 .with_protocol(CustomAssetProtocol)
18 .with_fetch(FileAssetFetch::default().with_root("resources"))
19 .with_event(|event| {
20 println!("Asset closure event: {event:#?}");
21 Ok(())
22 });
23
24 let handle = database.ensure("custom://part1.json")?;
25
26 while database.is_busy() {
27 database.maintain()?;
28 }
29
30 let contents = handle.access::<&CustomAsset>(&database).contents(&database);
31 println!("Custom chain contents: {contents:?}");
32
33 Ok(())
34}
35
36#[derive(Debug, Default, Deserialize)]
38struct CustomAsset {
39 content: String,
40 #[serde(default)]
41 next: Option<AssetPathStatic>,
42}
43
44impl CustomAsset {
45 fn contents(&self, database: &AssetDatabase) -> String {
46 let mut result = String::new();
47 let mut current = Some(self);
48 while let Some(asset) = current {
49 result.push_str(asset.content.as_str());
50 current = current
51 .as_ref()
52 .and_then(|asset| asset.next.as_ref())
53 .and_then(|path| path.find(database))
54 .and_then(|handle| handle.access_checked::<&Self>(database));
55 if current.is_some() {
56 result.push(' ');
57 }
58 }
59 result
60 }
61}
62
63struct CustomAssetProtocol;
65
66impl AssetProtocol for CustomAssetProtocol {
67 fn name(&self) -> &str {
68 "custom"
69 }
70
71 fn process_asset_bytes(
72 &mut self,
73 handle: AssetHandle,
74 storage: &mut World,
75 ) -> Result<(), Box<dyn Error>> {
76 let bytes = {
80 let mut bytes =
81 storage.component_mut::<true, AssetBytesAreReadyToProcess>(handle.entity())?;
82 std::mem::take(&mut bytes.0)
83 };
84 storage.remove::<(AssetBytesAreReadyToProcess,)>(handle.entity())?;
85
86 let asset = serde_json::from_slice::<CustomAsset>(&bytes)?;
88
89 if let Some(path) = asset.next.clone() {
91 let entity = storage.spawn((path, AssetAwaitsResolution))?;
94
95 storage.relate::<true, _>(AssetDependency, handle.entity(), entity)?;
98 }
99
100 storage.insert(handle.entity(), (asset,))?;
101 Ok(())
102 }
103}
104