khora_agents/asset_agent/agent.rs
1// Copyright 2025 eraflo
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The AssetAgent is responsible for managing asset loading and retrieval.
16
17use anyhow::{Context, Result};
18use khora_core::{
19 asset::{Asset, AssetHandle, AssetUUID},
20 vfs::VirtualFileSystem,
21};
22use khora_lanes::asset_lane::{AssetLoader, PackLoadingLane};
23use std::fs::File;
24
25use crate::asset_agent::loader::LoaderRegistry;
26
27/// The AssetAgent is responsible for managing asset loading and retrieval.
28pub struct AssetAgent {
29 /// The virtual file system for asset management.
30 vfs: VirtualFileSystem,
31 /// The loading lane for asset I/O operations.
32 loading_lane: PackLoadingLane,
33 /// The registry that manages asset loaders.
34 loaders: LoaderRegistry,
35}
36
37impl AssetAgent {
38 /// Creates a new `AssetAgent` with the given VFS and loading lane.
39 pub fn new(index_bytes: &[u8], data_file: File) -> Result<Self> {
40 let vfs = VirtualFileSystem::new(index_bytes)
41 .context("Failed to initialize VirtualFileSystem from index bytes")?;
42
43 let loading_lane = PackLoadingLane::new(data_file);
44
45 Ok(Self {
46 vfs,
47 loading_lane,
48 loaders: LoaderRegistry::new(),
49 })
50 }
51
52 /// Registers an `AssetLoader` for a specific asset type name.
53 ///
54 /// The `type_name` should match the one generated by the `xtask` packager
55 /// based on the file extension.
56 pub fn register_loader<A: Asset>(
57 &mut self,
58 type_name: &str,
59 loader: impl AssetLoader<A> + Send + Sync + 'static,
60 ) {
61 self.loaders.register::<A>(type_name, loader);
62 }
63
64 /// Loads, decodes, and returns a typed handle to an asset.
65 ///
66 /// This is the main, fully-featured loading method.
67 pub fn load<A: Asset>(&mut self, uuid: &AssetUUID) -> Result<AssetHandle<A>> {
68 let metadata = self.vfs.get_metadata(uuid).context("...")?;
69 let source = metadata.variants.get("default").context("...")?;
70 let bytes = self.loading_lane.load_asset_bytes(source)?;
71
72 let asset = self.loaders.load::<A>(&metadata.asset_type_name, &bytes)?;
73
74 Ok(AssetHandle::new(asset))
75 }
76}