chrisgliddon/bevy-skills

bevy-custom-assets

Use when implementing AssetLoader, depending on assets through LoadContext::loadbuilder().withsettings(..).load(..), deriving TypePath on a loader, reading with Reader::readtoend, or implementing the required Reader::seekable method in Bevy 0.19.

소스 보기

사용 방법

  1. 설치 명령을 복사하고 자신의 에이전트 환경에 설치하기 전에 소스 패키지를 확인하세요.
  2. 필요한 도구, 인증 정보, 지원 환경은 원본 문서에서 확인하세요.
  3. 입력과 원하는 산출물을 설명하고 출처와 결과를 대조하세요.
npx skills add https://github.com/chrisgliddon/bevy-skills --skill bevy-custom-assets

시작 전 확인

  • 설치에는 모델 구독, API 한도, 파일 접근 권한이 포함되지 않습니다.
  • 별점 수와 설치 수는 활동 지표이며 독립적인 품질·보안 검증이 아닙니다.
원본 Skill 문서

원본 저장소의 제목, 예시, 코드, 표, 링크, 이미지를 유지해 표시합니다.

Bevy 0.19 — Custom asset loaders

When to use this skill

  • Loading a custom binary or text format (proprietary game data, sidecar configs, etc.).
  • Producing an asset that depends on other assets (e.g. a level loader that pulls referenced textures).
  • Migrating LoadContext::loader() or an old NestedLoader to load_builder() / NestedLoadBuilder.
  • Needing async access to the underlying file (reader.read_to_end, reader.seekable()).
  • Compiler error: "MyLoader: TypePath is not implemented" — 0.18 made TypePath mandatory on loaders.

Canonical pattern

rust
use bevy::asset::io::Reader;
use bevy::asset::{Asset, AssetApp, AssetLoader, LoadContext};
use bevy::prelude::*;
use bevy::reflect::TypePath;
use serde::Deserialize;
use thiserror::Error;

#[derive(Asset, TypePath, Debug, Deserialize)]
pub struct LevelDef {
    pub name: String,
    pub gravity: f32,
    pub thumbnail: String, // path to a referenced texture asset
}

#[derive(TypePath)] // 0.18: required on the loader itself.
pub struct LevelLoader;

#[derive(Debug, Error)]
pub enum LevelLoaderError {
    #[error("io: {0}")]
    Io(#[from] std::io::Error),
    #[error("parse: {0}")]
    Parse(#[from] ron::error::SpannedError),
}

impl AssetLoader for LevelLoader {
    type Asset = LevelDef;
    type Settings = ();
    type Error = LevelLoaderError;

    async fn load(
        &self,
        reader: &mut dyn Reader,
        _settings: &Self::Settings,
        load_context: &mut LoadContext<'_>,
    ) -> Result<Self::Asset, Self::Error> {
        // Pull the whole file. For very large files prefer `seekable()`.
        let mut bytes = Vec::new();
        reader.read_to_end(&mut bytes).await?;
        let level: LevelDef = ron::de::from_bytes(&bytes)?;

        // Pull in a referenced asset so it loads alongside this one.
        // The resulting handle ends up tracked as a dependency.
        let _: Handle<Image> = load_context.load_builder().load(level.thumbnail.clone());

        Ok(level)
    }

    fn extensions(&self) -> &[&str] {
        &["level.ron"]
    }
}

pub struct LevelLoaderPlugin;
impl Plugin for LevelLoaderPlugin {
    fn build(&self, app: &mut App) {
        app.init_asset::<LevelDef>()
            .register_asset_loader(LevelLoader);
    }
}

Asking the reader for random access

rust
// Bevy 0.19 requires Reader implementations to expose `seekable()`.
# use bevy::asset::io::Reader;
# async fn _example(reader: &mut dyn Reader) -> std::io::Result<()> {
match reader.seekable() {
    Ok(seekable) => {
        // SeekableReader supports `seek(SeekFrom::Start(n))`, `seek(SeekFrom::End(-n))`, etc.
        let _ = seekable;
    }
    Err(_) => {
        // Source isn't seekable (e.g. HTTP backend). Fall back to streaming.
    }
}
# Ok(())
# }

Bevy 0.19 gotchas

  • `#[derive(TypePath)]` is required on the loader struct (not just the asset). 0.18 enforces this so loaders can be reflected. Without it: "MyLoader: TypePath is not implemented".
  • `LoadContext::path()` returns `AssetPath`, not &Path. To get the platform path, use .path() on it: ctx.path().path().
  • `LoadContext::asset_bytes()` is gone. Use let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; inside the load async fn, or reader.seekable() for random access.
  • Dependencies must be loaded through `LoadContext`. asset_server.load(...) from inside a loader does not register the result as a dependency of the asset being built — use load_context.load_builder().load(...) (or the load(...) convenience method) so AssetEvent::LoadedWithDependencies fires correctly.
  • `LoadContext::loader()` was replaced in 0.19. Use load_context.load_builder(). Immediate loads became load_value, dynamic loads became load_erased, and unknown-type loads became load_untyped builder operations.
  • Custom `Reader` implementations must define `seekable()` in 0.19. Return Ok(self) only when the type implements AsyncSeek; otherwise return Err(ReaderNotSeekableError).
  • `AssetLoader` is `async` but you can't tokio::spawn inside it — the executor is Bevy's, not Tokio's. Use bevy::tasks::futures_lite or bevy::tasks::AsyncComputeTaskPool for compute-heavy work.
  • `#[derive(Asset)]` is required on the asset type and combined with TypePath. The asset's Settings type must be Default + Serialize + DeserializeOwned + Send + Sync + 'static to participate in .meta files.
  • Extensions are matched on the full suffix. "level.ron" matches foo.level.ron but not foo.ron — useful for disambiguating from generic RON.

See also

  • bevy-assets — using a Handle<MyAsset> once it's loaded.
  • bevy-voxel-data — RON-driven asset patterns.
  • bevy-migration-0-17-to-0-18 — LoadContext::asset_bytes removal.
  • bevy-migration-0-18-to-0-19 — nested load builders and reader changes.

관련 작업

같은 저장소의 Skills

더 많은 Skills

모든 Skills