limnus_asset_registry/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/limnus
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5mod 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}