pub struct AssetServer { /* private fields */ }Expand description
Central coordinator for asset loading and caching.
The AssetServer manages:
- Asset loaders (registered by file extension)
- Asset storage (cached loaded assets)
- Loading queue (assets being loaded)
- Hot reloading (watching for file changes)
§Thread Safety
AssetServer is Send but NOT Sync - it should be accessed from a single
thread (typically the main thread). For multi-threaded asset loading, use
async handles and check loading state from the main thread.
§Example
use goud_engine::assets::{Asset, AssetServer};
struct MyAsset { data: String }
impl Asset for MyAsset {}
let mut server = AssetServer::new();
// Load returns a handle immediately
let handle = server.load::<MyAsset>("data/config.json");
// Asset loads in background, check state
match server.get_load_state(&handle) {
Some(state) => println!("Loading: {}", state),
None => println!("Not found"),
}Implementations§
Source§impl AssetServer
impl AssetServer
Sourcepub fn load_async<A: Asset>(&mut self, path: impl AsRef<Path>) -> AssetHandle<A>
pub fn load_async<A: Asset>(&mut self, path: impl AsRef<Path>) -> AssetHandle<A>
Loads an asset asynchronously using a background thread.
Returns a handle immediately in the Loading state. The actual file I/O
and parsing happen on a rayon thread pool. Call [process_loads] each
frame to drain completed results and transition handles to Loaded or
Failed.
§Deduplication
If an asset with the same path is already loaded or loading, the existing handle is returned without spawning a new background task.
§Arguments
path- Path to the asset file (relative to asset root)
§Example
let handle = server.load_async::<MyAsset>("data/config.test");
// ... later, in the game loop:
server.process_loads();
if server.is_loaded(&handle) {
let asset = server.get(&handle).unwrap();
}Source§impl AssetServer
impl AssetServer
Sourcepub fn process_loads(&mut self) -> usize
pub fn process_loads(&mut self) -> usize
Drains completed async load results and applies them to asset storage.
This must be called from the main thread (typically once per frame) to
transition async-loaded assets from Loading to Loaded or Failed.
§Returns
The number of load results processed in this call.
Source§impl AssetServer
impl AssetServer
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new asset server with the default asset root (“assets/”).
§Example
use goud_engine::assets::AssetServer;
let server = AssetServer::new();Sourcepub fn asset_root(&self) -> &Path
pub fn asset_root(&self) -> &Path
Returns the asset root directory.
§Example
use goud_engine::assets::AssetServer;
let server = AssetServer::with_root("game_assets");
assert_eq!(server.asset_root().to_str().unwrap(), "game_assets");Sourcepub fn set_asset_root(&mut self, root: impl AsRef<Path>)
pub fn set_asset_root(&mut self, root: impl AsRef<Path>)
Source§impl AssetServer
impl AssetServer
Sourcepub fn register_loader<L: AssetLoader>(&mut self, loader: L)
pub fn register_loader<L: AssetLoader>(&mut self, loader: L)
Registers an asset loader for specific file extensions.
Loaders are matched by file extension. If multiple loaders support the same extension, the most recently registered one is used.
§Arguments
loader- The asset loader to register
§Example
use goud_engine::assets::{Asset, AssetServer, AssetLoader, LoadContext, AssetLoadError};
#[derive(Clone)]
struct TextAsset { content: String }
impl Asset for TextAsset {}
#[derive(Clone)]
struct TextLoader;
impl AssetLoader for TextLoader {
type Asset = TextAsset;
type Settings = ();
fn extensions(&self) -> &[&str] {
&["txt"]
}
fn load<'a>(
&'a self,
bytes: &'a [u8],
_settings: &'a Self::Settings,
_context: &'a mut LoadContext,
) -> Result<Self::Asset, AssetLoadError> {
let content = String::from_utf8(bytes.to_vec())
.map_err(|e| AssetLoadError::decode_failed(e.to_string()))?;
Ok(TextAsset { content })
}
}
let mut server = AssetServer::new();
server.register_loader(TextLoader);Sourcepub fn register_loader_with_settings<L: AssetLoader>(
&mut self,
loader: L,
settings: L::Settings,
)
pub fn register_loader_with_settings<L: AssetLoader>( &mut self, loader: L, settings: L::Settings, )
Registers an asset loader with custom settings.
§Arguments
loader- The asset loader to registersettings- Custom settings for this loader
Sourcepub fn has_loader_for_extension(&self, extension: &str) -> bool
pub fn has_loader_for_extension(&self, extension: &str) -> bool
Returns true if a loader is registered for the given extension.
§Example
use goud_engine::assets::AssetServer;
let server = AssetServer::new();
// Assuming TextLoader is registered for "txt"
// assert!(server.has_loader_for_extension("txt"));
assert!(!server.has_loader_for_extension("unknown"));Sourcepub fn has_loader_for_type<A: Asset>(&self) -> bool
pub fn has_loader_for_type<A: Asset>(&self) -> bool
Returns true if a loader is registered for the given asset type.
Sourcepub fn loader_count(&self) -> usize
pub fn loader_count(&self) -> usize
Returns the number of registered loaders.
Source§impl AssetServer
impl AssetServer
Sourcepub fn load<A: Asset>(&mut self, path: impl AsRef<Path>) -> AssetHandle<A>
pub fn load<A: Asset>(&mut self, path: impl AsRef<Path>) -> AssetHandle<A>
Loads an asset from a path (relative to asset root), returning a handle immediately.
The asset loads synchronously (blocking). The handle is valid even if loading
fails — check with get_load_state().
Sourcepub fn load_from_bytes<A: Asset>(
&mut self,
path: impl AsRef<Path>,
bytes: &[u8],
) -> AssetHandle<A>
pub fn load_from_bytes<A: Asset>( &mut self, path: impl AsRef<Path>, bytes: &[u8], ) -> AssetHandle<A>
Loads an asset from pre-fetched bytes, returning a handle.
This is the platform-agnostic entry point for loading assets when you already have the raw bytes (e.g., from a web fetch, embedded resource, or custom I/O layer). The bytes are run through the registered loader matched by the path’s file extension.
Returns an existing handle if an asset with the same path is already loaded.
§Arguments
path- Logical asset path (used for loader lookup and deduplication)bytes- Raw asset bytes to parse
§Example
use goud_engine::assets::{Asset, AssetServer, AssetLoader, LoadContext, AssetLoadError};
#[derive(Clone)]
struct JsonAsset { data: String }
impl Asset for JsonAsset {}
#[derive(Clone)]
struct JsonLoader;
impl AssetLoader for JsonLoader {
type Asset = JsonAsset;
type Settings = ();
fn extensions(&self) -> &[&str] { &["json"] }
fn load<'a>(
&'a self, bytes: &'a [u8], _: &'a (), _: &'a mut LoadContext,
) -> Result<Self::Asset, AssetLoadError> {
Ok(JsonAsset { data: String::from_utf8_lossy(bytes).into_owned() })
}
}
let mut server = AssetServer::new();
server.register_loader(JsonLoader);
let bytes = br#"{"key": "value"}"#;
let handle = server.load_from_bytes::<JsonAsset>("config.json", bytes);
assert!(server.is_loaded(&handle));Sourcepub fn get<A: Asset>(&self, handle: &AssetHandle<A>) -> Option<&A>
pub fn get<A: Asset>(&self, handle: &AssetHandle<A>) -> Option<&A>
Gets a reference to a loaded asset.
Returns None if the asset is not loaded or the handle is invalid.
§Example
use goud_engine::assets::{Asset, AssetServer};
struct MyAsset { value: i32 }
impl Asset for MyAsset {}
let mut server = AssetServer::new();
let handle = server.load::<MyAsset>("data/config.json");
if let Some(asset) = server.get(&handle) {
println!("Asset value: {}", asset.value);
}Sourcepub fn get_mut<A: Asset>(&mut self, handle: &AssetHandle<A>) -> Option<&mut A>
pub fn get_mut<A: Asset>(&mut self, handle: &AssetHandle<A>) -> Option<&mut A>
Gets a mutable reference to a loaded asset.
Returns None if the asset is not loaded or the handle is invalid.
Sourcepub fn is_loaded<A: Asset>(&self, handle: &AssetHandle<A>) -> bool
pub fn is_loaded<A: Asset>(&self, handle: &AssetHandle<A>) -> bool
Returns true if the handle points to a valid, loaded asset.
§Example
use goud_engine::assets::{Asset, AssetServer, AssetHandle};
struct MyAsset;
impl Asset for MyAsset {}
let server = AssetServer::new();
let handle = AssetHandle::<MyAsset>::INVALID;
assert!(!server.is_loaded(&handle));Sourcepub fn get_load_state<A: Asset>(
&self,
handle: &AssetHandle<A>,
) -> Option<AssetState>
pub fn get_load_state<A: Asset>( &self, handle: &AssetHandle<A>, ) -> Option<AssetState>
Returns the loading state for a handle, or None if not tracked.
Sourcepub fn unload<A: Asset>(&mut self, handle: &AssetHandle<A>) -> Option<A>
pub fn unload<A: Asset>(&mut self, handle: &AssetHandle<A>) -> Option<A>
Unloads an asset, freeing its memory.
The handle becomes invalid after this call.
§Returns
The unloaded asset if it was loaded, otherwise None.
§Example
use goud_engine::assets::{Asset, AssetServer};
struct Texture { width: u32 }
impl Asset for Texture {}
let mut server = AssetServer::new();
let handle = server.load::<Texture>("texture.png");
// Later, unload to free memory
let texture = server.unload(&handle);
assert!(!server.is_loaded(&handle));Sourcepub fn dependency_graph(&self) -> &DependencyGraph
pub fn dependency_graph(&self) -> &DependencyGraph
Returns a reference to the dependency graph.
Useful for inspecting asset relationships or computing cascade reload orders externally.
Sourcepub fn dependency_graph_mut(&mut self) -> &mut DependencyGraph
pub fn dependency_graph_mut(&mut self) -> &mut DependencyGraph
Returns a mutable reference to the dependency graph.
Sourcepub fn reload_by_path(&mut self, path: &str) -> bool
pub fn reload_by_path(&mut self, path: &str) -> bool
Reloads an asset from disk by its path, using the type-erased loader.
This is used by the hot-reload watcher to reload assets without knowing their concrete type at compile time.
§Returns
true if the asset was successfully reloaded, false if the path
has no registered loader or the reload failed.
Sourcepub fn get_cascade_order(&self, changed_path: &str) -> Vec<String>
pub fn get_cascade_order(&self, changed_path: &str) -> Vec<String>
Returns the cascade reload order for a changed asset path.
This delegates to [DependencyGraph::get_cascade_order] and
returns the list of asset paths that should be reloaded, in
the correct order, when changed_path changes.
Sourcepub fn loaded_count<A: Asset>(&self) -> usize
pub fn loaded_count<A: Asset>(&self) -> usize
Returns the number of loaded assets of a specific type.
§Example
use goud_engine::assets::{Asset, AssetServer};
struct Texture;
impl Asset for Texture {}
let server = AssetServer::new();
assert_eq!(server.loaded_count::<Texture>(), 0);Sourcepub fn total_loaded_count(&self) -> usize
pub fn total_loaded_count(&self) -> usize
Returns the total number of loaded assets across all types.
Sourcepub fn registered_type_count(&self) -> usize
pub fn registered_type_count(&self) -> usize
Returns the number of registered asset types.
Sourcepub fn clear_type<A: Asset>(&mut self)
pub fn clear_type<A: Asset>(&mut self)
Clears all loaded assets of a specific type.
This frees memory but does not affect registered loaders.
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Clears all loaded assets from all types.
This frees memory but does not affect registered loaders.
Sourcepub fn handles<A: Asset>(&self) -> impl Iterator<Item = AssetHandle<A>> + '_
pub fn handles<A: Asset>(&self) -> impl Iterator<Item = AssetHandle<A>> + '_
Returns an iterator over all loaded asset handles of a specific type.
Sourcepub fn iter<A: Asset>(&self) -> impl Iterator<Item = (AssetHandle<A>, &A)>
pub fn iter<A: Asset>(&self) -> impl Iterator<Item = (AssetHandle<A>, &A)>
Returns an iterator over all loaded assets of a specific type.
Sourcepub fn create_hot_reload_watcher(&self) -> Result<HotReloadWatcher>
pub fn create_hot_reload_watcher(&self) -> Result<HotReloadWatcher>
Creates a hot reload watcher for this asset server.
The watcher will detect file changes in the asset root directory and automatically reload modified assets.
§Errors
Returns an error if the file watcher cannot be initialized.
§Example
use goud_engine::assets::AssetServer;
let mut server = AssetServer::new();
let mut watcher = server.create_hot_reload_watcher().unwrap();
// In game loop
loop {
watcher.process_events(&mut server);
// ... rest of game loop
}Sourcepub fn create_hot_reload_watcher_with_config(
&self,
config: HotReloadConfig,
) -> Result<HotReloadWatcher>
pub fn create_hot_reload_watcher_with_config( &self, config: HotReloadConfig, ) -> Result<HotReloadWatcher>
Creates a hot reload watcher with custom configuration.
§Errors
Returns an error if the file watcher cannot be initialized.
§Example
use goud_engine::assets::{AssetServer, HotReloadConfig};
use std::time::Duration;
let mut server = AssetServer::new();
let config = HotReloadConfig::new()
.with_debounce(Duration::from_millis(200))
.watch_extension("png")
.watch_extension("json");
let mut watcher = server.create_hot_reload_watcher_with_config(config).unwrap();
// In game loop
loop {
watcher.process_events(&mut server);
// ... rest of game loop
}Trait Implementations§
Source§impl Debug for AssetServer
impl Debug for AssetServer
Auto Trait Implementations§
impl Freeze for AssetServer
impl !RefUnwindSafe for AssetServer
impl Send for AssetServer
impl !Sync for AssetServer
impl Unpin for AssetServer
impl UnsafeUnpin for AssetServer
impl !UnwindSafe for AssetServer
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian().