|
| 1 | +//! A Sketch asset represents a source file containing user code for a Processing sketch. |
| 2 | +//! |
| 3 | +//! Sketches are loaded through Bevy's asset system, which provides automatic file watching |
| 4 | +//! and change detection. This enables hot-reloading workflows where artists can edit their |
| 5 | +//! sketch code and see changes reflected immediately without restarting. |
| 6 | +//! |
| 7 | +//! This module is intentionally language-agnostic — it only handles loading source text from |
| 8 | +//! disk. Language-specific crates (like `processing_pyo3`) are responsible for executing the |
| 9 | +//! source and binding it to the Processing API. |
| 10 | +
|
| 11 | +use bevy::{ |
| 12 | + asset::{AssetLoader, LoadContext, io::Reader}, |
| 13 | + prelude::*, |
| 14 | +}; |
| 15 | +use std::path::PathBuf; |
| 16 | + |
| 17 | +/// Plugin that registers the Sketch asset type and its loader. |
| 18 | +pub struct LivecodePlugin; |
| 19 | + |
| 20 | +impl Plugin for LivecodePlugin { |
| 21 | + fn build(&self, app: &mut App) { |
| 22 | + app.init_asset::<Sketch>() |
| 23 | + .init_asset_loader::<SketchLoader>(); |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +/// A sketch source file loaded as a Bevy asset. |
| 28 | +/// |
| 29 | +/// The `Sketch` asset contains the raw source code as a string. It does not interpret |
| 30 | +/// or execute the code — that responsibility belongs to language-specific crates. |
| 31 | +#[derive(Asset, TypePath, Debug)] |
| 32 | +pub struct Sketch { |
| 33 | + /// The source code contents of the sketch file. |
| 34 | + pub source: String, |
| 35 | + |
| 36 | + /// The original file path. |
| 37 | + pub path: PathBuf, |
| 38 | +} |
| 39 | + |
| 40 | +/// Loads sketch files from disk. |
| 41 | +/// |
| 42 | +/// Currently supports `.py` files, but the loader is designed to be extended |
| 43 | +/// for other languages in the future. |
| 44 | +#[derive(Default)] |
| 45 | +pub struct SketchLoader; |
| 46 | + |
| 47 | +impl AssetLoader for SketchLoader { |
| 48 | + type Asset = Sketch; |
| 49 | + type Settings = (); |
| 50 | + type Error = std::io::Error; |
| 51 | + |
| 52 | + async fn load( |
| 53 | + &self, |
| 54 | + reader: &mut dyn Reader, |
| 55 | + _settings: &Self::Settings, |
| 56 | + load_context: &mut LoadContext<'_>, |
| 57 | + ) -> Result<Self::Asset, Self::Error> { |
| 58 | + let mut source = String::new(); |
| 59 | + |
| 60 | + let mut bytes = Vec::new(); |
| 61 | + reader.read_to_end(&mut bytes).await?; |
| 62 | + |
| 63 | + if let Ok(utf8) = str::from_utf8(&bytes) { |
| 64 | + source = utf8.to_string(); |
| 65 | + } |
| 66 | + |
| 67 | + let asset_path = load_context.path(); |
| 68 | + let path: PathBuf = asset_path.path().to_path_buf(); |
| 69 | + |
| 70 | + Ok(Sketch { source, path }) |
| 71 | + } |
| 72 | + |
| 73 | + fn extensions(&self) -> &[&str] { |
| 74 | + &["py"] |
| 75 | + } |
| 76 | +} |
0 commit comments