bevy_cache/system_param.rs
1use bevy::ecs::system::SystemParam;
2use bevy::prelude::*;
3use std::time::Duration;
4use std::{io::Read, path::Path};
5
6use crate::{CacheConfig, CacheEntry, CacheError, CacheManifest};
7
8/// Combined system parameter for the cache manifest and config resources.
9///
10/// This removes the need to request both `ResMut<CacheManifest>` and
11/// `Res<CacheConfig>` in every system that interacts with the cache.
12///
13/// ```rust,ignore
14/// use bevy::prelude::*;
15/// use bevy_cache::prelude::*;
16///
17/// fn cache_screenshot(
18/// mut cache: Cache,
19/// asset_server: Res<AssetServer>,
20/// ) {
21/// cache
22/// .store(
23/// "screenshots/title",
24/// "png",
25/// std::io::Cursor::new(vec![1, 2, 3]),
26/// None,
27/// )
28/// .expect("cache write failed");
29///
30/// let _handle: Handle<Image> = cache
31/// .load_cached(&asset_server, "screenshots/title")
32/// .expect("cache load failed");
33/// }
34/// ```
35#[derive(SystemParam)]
36pub struct Cache<'w> {
37 manifest: ResMut<'w, CacheManifest>,
38 config: Res<'w, CacheConfig>,
39}
40
41impl<'w> Cache<'w> {
42 pub fn cache_dir(&self) -> &Path {
43 self.config.cache_dir.as_path()
44 }
45
46 /// Returns the cache configuration resource.
47 pub fn config(&self) -> &CacheConfig {
48 self.config.as_ref()
49 }
50
51 /// Returns the cache manifest resource.
52 pub fn manifest(&self) -> &CacheManifest {
53 self.manifest.as_ref()
54 }
55
56 /// Returns the cache manifest resource mutably.
57 pub fn manifest_mut(&mut self) -> &mut CacheManifest {
58 self.manifest.as_mut()
59 }
60
61 /// Store data in the cache under `key` using the given file extension.
62 pub fn store<R: Read>(
63 &mut self,
64 key: &str,
65 extension: &str,
66 reader: R,
67 max_age: Option<Duration>,
68 ) -> Result<(), CacheError> {
69 self.manifest
70 .store(self.config.as_ref(), key, extension, reader, max_age)
71 }
72
73 /// Remove a cache entry and its backing file from disk.
74 pub fn remove(&mut self, key: &str) -> Result<(), CacheError> {
75 self.manifest.remove(self.config.as_ref(), key)
76 }
77
78 /// Check whether a key exists in the manifest.
79 pub fn contains(&self, key: &str) -> bool {
80 self.manifest.contains(key)
81 }
82
83 /// Get a manifest entry by key.
84 pub fn get(&self, key: &str) -> Option<&CacheEntry> {
85 self.manifest.get(key)
86 }
87
88 /// Return the `cache://` asset path for `key`, if present.
89 pub fn asset_path(&self, key: &str) -> Option<String> {
90 self.manifest.asset_path(key)
91 }
92
93 /// Check whether the cached file for `key` still exists on disk.
94 pub fn is_cached(&self, key: &str) -> bool {
95 self.manifest.is_cached(self.config.as_ref(), key)
96 }
97
98 /// Returns the total manifest-reported size of cached data in bytes.
99 pub fn total_size_bytes(&self) -> u64 {
100 self.manifest.total_size_bytes()
101 }
102
103 /// Load a cached asset path through the provided [`AssetServer`].
104 ///
105 /// This returns `None` when the key does not exist in the manifest.
106 pub fn load<A: Asset>(&self, asset_server: &AssetServer, key: &str) -> Option<Handle<A>> {
107 self.asset_path(key).map(|path| asset_server.load(path))
108 }
109
110 /// Load a cached asset through the provided [`AssetServer`], returning an
111 /// error when the manifest entry is missing or stale.
112 pub fn load_cached<A: Asset>(
113 &self,
114 asset_server: &AssetServer,
115 key: &str,
116 ) -> Result<Handle<A>, CacheError> {
117 self.manifest
118 .load_cached(self.config.as_ref(), key, asset_server)
119 }
120
121 /// Returns the modified asset for `handle` when a matching
122 /// [`AssetEvent::Modified`] is present in `events`.
123 ///
124 /// This is only available with the `hot_reload` feature enabled.
125 #[cfg(feature = "hot_reload")]
126 pub fn get_if_modified<'a, A: Asset>(
127 &self,
128 handle: &Handle<A>,
129 assets: &'a Assets<A>,
130 messages: &'a mut MessageReader<AssetEvent<A>>,
131 ) -> Option<&'a A> {
132 for event in messages.read() {
133 if let AssetEvent::Modified { id } = event {
134 if *id == handle.id() {
135 return assets.get(handle);
136 }
137 }
138 }
139
140 None
141 }
142}