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}