limnus_asset_registry/
lib.rs1mod id_gen;
6mod idx_gen;
7
8use crate::id_gen::IdAssigner;
9use chunk_reader::get_platform_reader;
10use limnus_app::prelude::*;
11use limnus_assets::prelude::*;
12use limnus_assets_loader::ResourceStorage;
13use limnus_assets_loader::{AssetLoaderRegistry, LoadError, WrappedAssetLoaderRegistry};
14use limnus_default_stages::First;
15use limnus_loader::{Blob, LoaderReceiver, LoaderSender, load};
16use limnus_local_resource::LocalResourceStorage;
17use limnus_resource::prelude::Resource;
18use limnus_system_params::{LoReAll, Re, ReAll, ReM};
19use message_channel::{Channel, Receiver, Sender};
20use std::any::TypeId;
21use std::collections::HashMap;
22use std::sync::{Arc, Mutex};
23use tracing::debug;
24
25#[derive(Debug)]
26pub enum Phase {
27 Loading,
28 Error,
29 Defined,
30}
31
32#[derive(Debug)]
33pub struct AssetInfo {
34 pub name: AssetName,
35 pub phase: Phase,
36}
37
38type TypeIdMap<T> = HashMap<TypeId, T>;
39
40#[derive(Debug, Resource)]
41pub struct AssetRegistry {
42 infos: HashMap<RawWeakId, AssetInfo>,
43 sender: Sender<Blob>,
44 id_assigner: IdAssigner,
45 converters: Arc<Mutex<AssetLoaderRegistry>>,
46 #[allow(unused)]
47 drop_channel_receiver: Receiver<DropMessage>,
48}
49
50impl AssetRegistry {
51 #[must_use]
52 pub fn new(
53 sender: Sender<Blob>,
54 asset_loader_registry: Arc<Mutex<AssetLoaderRegistry>>,
55 ) -> Self {
56 let (drop_channel_sender, drop_channel_receiver) = Channel::create();
57 Self {
58 infos: HashMap::new(),
59 sender,
60 id_assigner: IdAssigner::new(drop_channel_sender),
61 converters: asset_loader_registry,
62 drop_channel_receiver,
63 }
64 }
65
66 pub fn load<T: Asset>(&mut self, name: impl Into<AssetName>) -> Id<T> {
67 let asset_name = name.into();
68 debug!(asset_name=%asset_name, "Loading");
69 let reader = get_platform_reader("assets/");
70 let typed_id = self.id_assigner.allocate::<T>(asset_name);
71 let raw_type_id: RawWeakId = (&typed_id).into();
72 self.infos.insert(
73 raw_type_id,
74 AssetInfo {
75 name: asset_name,
76 phase: Phase::Loading,
77 },
78 );
79 let sender = self.sender.clone();
80 {
81 future_runner::run_future(async move {
82 load(reader, &sender, asset_name, raw_type_id).await;
83 });
84 }
85 typed_id
86 }
87
88 pub fn allocate_id<T: Asset>(&mut self, name: impl Into<AssetName>) -> Id<T> {
89 let asset_name = name.into();
90 self.id_assigner.allocate::<T>(asset_name)
91 }
92
93 #[must_use]
94 pub fn name<A: Asset>(&self, id: Id<A>) -> Option<AssetName> {
95 let raw_id = (&id).into();
96 self.name_raw(raw_id)
97 }
98
99 #[must_use]
100 pub fn name_raw(&self, raw_id: RawWeakId) -> Option<AssetName> {
101 self.infos.get(&raw_id).map(|info| info.name)
102 }
103
104 pub fn blob_loaded(
105 &mut self,
106 id: RawWeakId,
107 octets: &[u8],
108 resources: &mut ResourceStorage,
109 local_resources: &mut LocalResourceStorage,
110 ) -> Result<(), LoadError> {
111 self.infos.get_mut(&id).unwrap().phase = Phase::Defined;
112 self.converters
113 .lock()
114 .unwrap()
115 .convert_and_insert(id, octets, resources, local_resources)
116 }
117
118 pub fn asset_id_dropped<A: Asset>(&mut self, id: Id<A>) {
119 self.infos.remove(&(&id).into());
120 self.id_assigner.remove(id);
121 }
122}
123
124pub struct AssetRegistryPlugin;
125
126impl Plugin for AssetRegistryPlugin {
127 fn build(&self, app: &mut App) {
128 let sender = app.resource_take::<LoaderSender>();
129 {
130 let asset_loader_registry = app.resource::<WrappedAssetLoaderRegistry>();
131 app.insert_resource(AssetRegistry::new(
132 sender.sender,
133 Arc::clone(&asset_loader_registry.value),
134 ));
135 }
136 app.add_system(First, tick);
137 }
138}
139
140fn tick(
141 loader_receiver: Re<LoaderReceiver>,
142 mut asset_container: ReM<AssetRegistry>,
143 mut mut_access_to_resources: ReAll,
144 mut mut_access_to_local_resources: LoReAll,
145) {
146 if let Some(blob) = loader_receiver.receiver.try_recv() {
147 debug!("loaded {:?}, starting conversion", blob);
148 asset_container
149 .blob_loaded(
150 blob.id,
151 &blob.content,
152 &mut mut_access_to_resources,
153 &mut mut_access_to_local_resources,
154 )
155 .expect("couldn't convert");
156 }
157}