1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use std::{hash::Hash, path::PathBuf};

use ahash::AHashMap;
use bevy::{
    asset::{AssetPath, RecursiveDependencyLoadState},
    prelude::*,
};
use enum_iterator::Sequence;
use iyes_progress::Progress;

use crate::names::FileStem;

pub trait AssetCollection {
    type Key;
    type Asset: Asset;

    fn get(&self, scene_type: Self::Key) -> &Handle<Self::Asset>;
}

pub(crate) trait AssetCollectionLoader
where
    Self: Sized + AssetCollection,
    Self::Key: Eq + Hash + FileStem + Sequence,
{
    const DIRECTORY: &'static str;
    const SUFFIX: &'static str;

    fn new(map: AHashMap<Self::Key, Handle<Self::Asset>>) -> Self;

    /// Return asset label to be passed to the asset server to load all assets
    /// from the collection.
    fn label() -> Option<String>;

    /// Initialize the collection by (starting) loading of all assets of the
    /// collection.
    fn init(server: &AssetServer) -> Self {
        Self::new(AHashMap::from_iter(enum_iterator::all::<Self::Key>().map(
            |key| {
                let mut model_path = PathBuf::new();
                model_path.push(Self::DIRECTORY);
                model_path.push(format!("{}.{}", key.stem(), Self::SUFFIX));
                let mut asset_path = AssetPath::from(model_path);
                if let Some(label) = Self::label() {
                    asset_path = asset_path.with_label(label);
                }
                let handle = server.load(asset_path);
                (key, handle)
            },
        )))
    }

    /// Returns progress of the loading.
    ///
    /// It shall not be called before [`Self::init`].
    ///
    /// # Panics
    ///
    /// Panics if loading any of the assets is either failed or unknown.
    fn progress(&self, server: &AssetServer) -> Progress {
        enum_iterator::all::<Self::Key>()
            .map(
                |key| match server.get_recursive_dependency_load_state(self.get(key)) {
                    Some(load_state) => match load_state {
                        RecursiveDependencyLoadState::Failed => panic!("Model loading failed"),
                        RecursiveDependencyLoadState::NotLoaded => false.into(),
                        RecursiveDependencyLoadState::Loading => false.into(),
                        RecursiveDependencyLoadState::Loaded => true.into(),
                    },
                    None => panic!(
                        "Unknown asset: {}/{}.{}",
                        Self::DIRECTORY,
                        key.stem(),
                        Self::SUFFIX
                    ),
                },
            )
            .reduce(|a, b| a + b)
            .unwrap_or(Progress { done: 0, total: 0 })
    }
}