mcpField
B
bevy-custom-assets

bevy-custom-assets

github.com/chrisgliddon開発2683 回インストール9 週間前に更新
リポジトリ

bevy-custom-assets について

Bevy 0.19でカスタムアセットローダーを実装する開発者向けのスキルです。非同期ファイルアクセス、依存アセットの読み込み、API変更点を扱います。

主な機能

  1. 01カスタムアセットローダーの実装
  2. 02非同期読み込みとランダムアクセス
  3. 03LoadContext経由の依存読み込み
  4. 04Bevy 0.19のAPI変更への対応

活用シーン

  1. 01独自のバイナリ形式やテキスト形式の読み込み
  2. 02参照アセットを扱うレベルローダーの作成
  3. 03旧式のネスト読み込みコードの移行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/chrisgliddon/bevy-skills --skill bevy-custom-assets

インストール後、Claude Code で/bevy-custom-assetsを入力して読み込まれたか確認します。

詳細

Bevy 0.19 — カスタムアセットローダー

このスキルを使う場面

  • 独自のバイナリ形式またはテキスト形式(独自のゲームデータ、サイドカーレ設定など)を読み込む場合。
  • 他のアセットに依存するアセットを生成する場合(参照先のテクスチャを読み込むレベルローダーなど)。
  • LoadContext::loader() または古い NestedLoader から load_builder() / NestedLoadBuilder に移行する場合。
  • 基になるファイルへの非同期アクセス(reader.read_to_end、reader.seekable())が必要な場合。
  • コンパイラーエラー:"MyLoader: TypePath is not implemented" — 0.18 ではローダーに TypePath が必須になりました。

標準的なパターン

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);
    }
}

ランダムアクセス用に Reader を要求する

// 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 の注意点

  • ローダー構造体には #[derive(TypePath)] が必須です(アセットだけでなく、ローダーにも必要です)。0.18 ではローダーをリフレクション可能にするため、これが必須になりました。指定しないと、"MyLoader: TypePath is not implemented" というエラーが発生します。
  • LoadContext::path() が返すのは AssetPath であり、&Path ではありません。プラットフォームのパスを取得するには、AssetPath の .path() を使います:ctx.path().path()。
  • LoadContext::asset_bytes() は削除されました。 load 非同期関数内で let mut bytes = Vec::new(); reader.read_to_end(&mut bytes).await?; を使うか、ランダムアクセスには reader.seekable() を使います。
  • 依存関係は LoadContext を通じて読み込む必要があります。 ローダー内で asset_server.load(...) を呼び出しても、生成中のアセットの依存関係として結果は登録されません。AssetEvent::LoadedWithDependencies が正しく発火するように、load_context.load_builder().load(...)(または簡便メソッドの load(...))を使います。
  • LoadContext::loader() は 0.19 で置き換えられました。 load_context.load_builder() を使います。即時ロードは load_value に、動的ロードは load_erased に、型が不明なロードはビルダー操作の load_untyped に置き換えられました。
  • 独自の Reader 実装では、0.19 から seekable() の定義が必須です。 型が AsyncSeek を実装している場合に限り Ok(self) を返し、それ以外の場合は Err(ReaderNotSeekableError) を返します。
  • AssetLoader は非同期ですが、その内部で tokio::spawn は使用できません。エグゼキューターは Tokio ではなく Bevy のものです。計算負荷の高い処理には bevy::tasks::futures_lite または bevy::tasks::AsyncComputeTaskPool を使います。
  • アセット型には #[derive(Asset)] が必須で、TypePath と組み合わせて使います。 .meta ファイルに対応させるには、アセットの Settings 型が Default + Serialize + DeserializeOwned + Send + Sync + 'static を満たす必要があります。
  • 拡張子はサフィックス全体で照合されます。 "level.ron" は foo.level.ron に一致しますが、foo.ron には一致しません。汎用的な RON と区別する場合に便利です。

関連項目

  • bevy-assets — 読み込み済みの Handle<MyAsset> の使用方法。
  • bevy-voxel-data — RON 駆動のアセットパターン。
  • bevy-migration-0-17-to-0-18 — LoadContext::asset_bytes の削除。
  • bevy-migration-0-18-to-0-19 — ネストされたロードビルダーと Reader の変更。

コメント