diff --git a/Cargo.lock b/Cargo.lock index 3240431..a615d72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2484,6 +2484,8 @@ name = "scratch-bevy" version = "0.1.0" dependencies = [ "bevy", + "futures-lite", + "zip", ] [[package]] @@ -3295,3 +3297,15 @@ name = "xi-unicode" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + +[[package]] +name = "zip" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080" +dependencies = [ + "byteorder", + "crc32fast", + "crossbeam-utils", + "flate2", +] diff --git a/Cargo.toml b/Cargo.toml index 85b5ecd..e5374e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,8 @@ rust-version = "1.65" [dependencies] bevy = "0.9.1" +futures-lite = "1.12.0" +zip = { version = "0.6.3", default-features = false, features = ["deflate"] } [features] # remember to disable bevy's "dynamic" feature for release builds diff --git a/assets/Infinite Toebeans.sb3 b/assets/Infinite Toebeans.sb3 new file mode 100644 index 0000000..7f34553 Binary files /dev/null and b/assets/Infinite Toebeans.sb3 differ diff --git a/src/main.rs b/src/main.rs index ebd8105..2bfc40d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,20 @@ use bevy::{ prelude::*, + tasks::*, time::FixedTimestep, window::*, }; +use futures_lite::future; const TIME_STEP: f64 = 1. / 30.; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] + +enum AppState { + Loading, + Running, +} + fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { @@ -20,12 +29,69 @@ fn main() { }, ..default() })) + .add_plugin(ScratchLoadingScreenPlugin) .add_plugin(ScratchStagePlugin) .add_plugin(ScratchDemoProjectPlugin) .add_system(close_on_esc) .run(); } +// +// Loading screen +// + +pub struct ScratchLoadingScreenPlugin; + +#[derive(Component)] +struct LoadingScreen; + +impl Plugin for ScratchLoadingScreenPlugin { + fn build(&self, app: &mut App) { + app + .add_state(AppState::Loading) + .add_system_set( + SystemSet::on_enter(AppState::Loading) + .with_system(ScratchLoadingScreenPlugin::start_loading_screen) + ) + .add_system_set( + SystemSet::on_update(AppState::Loading) + .with_system(ScratchLoadingScreenPlugin::update_loading_screen) + ) + .add_system_set( + SystemSet::on_exit(AppState::Loading) + .with_system(ScratchLoadingScreenPlugin::stop_loading_screen) + ); + } +} + +impl ScratchLoadingScreenPlugin { + + fn start_loading_screen(mut commands: Commands, asset_server: Res) { + commands.spawn(( + SpriteBundle { + texture: asset_server.load("squirrel.png"), + ..default() + }, + LoadingScreen + )); + } + + fn update_loading_screen(mut loading_screen_query: Query<&mut Transform, With>) { + let one_degree_in_radians: f32 = (1.0_f32).to_radians(); + + for mut transform in &mut loading_screen_query { + transform.rotate_z(-one_degree_in_radians); + } + } + + fn stop_loading_screen(mut commands: Commands, mut loading_screen_query: Query>) { + for loading_screen in &mut loading_screen_query { + commands.entity(loading_screen).despawn(); + } + + } +} + // // Sprite // @@ -109,31 +175,46 @@ pub struct ScratchDemoProjectPlugin; impl Plugin for ScratchDemoProjectPlugin { fn build(&self, app: &mut App) { app - .add_startup_system(add_demo_project_sprites); + .add_startup_system(project_load) + .add_system_set( + SystemSet::on_update(AppState::Loading) + .with_system(project_check_load) + ); } } -fn add_demo_project_sprites(mut commands: Commands, asset_server: Res) { - commands.spawn( - SpriteBundle { - texture: asset_server.load("squirrel.png"), - transform: Transform::from_scale(Vec3::new(0.5, 0.5, 1.)), - ..default() - }) - .insert(Name("Sprite 1".to_string())) - .insert(ScratchScripts(vec![ - ScratchCode::MoveOneStep, - ScratchCode::TurnClockwise, - ])); - commands.spawn( - SpriteBundle { - texture: asset_server.load("squirrel.png"), - transform: Transform::from_scale(Vec3::new(0.5, 0.5, 1.)), - ..default() - }) - .insert(Name("Sprite 2".to_string())) - .insert(ScratchScripts(vec![ - ScratchCode::MoveTwoSteps, - ScratchCode::TurnCounterClockwise, - ])); +#[derive(Resource)] +struct ProjectZip(HandleUntyped); + +#[derive(Resource)] +struct ProjectLoadTask(Task); + +fn project_load(mut commands: Commands, asset_server: Res) { + info!("Starting project load"); + let project_handle = asset_server.load_untyped("Infinite Toebeans.sb3"); + commands.insert_resource(ProjectZip(project_handle)) +} + +fn project_check_load(mut commands: Commands, mut app_state: ResMut>, project_zip: Option>, mut project_task: Option>) { + if let Some(project_zip) = project_zip { + if project_zip.is_added() { + info!("Project archive is loaded. Time to unpack..."); + let thread_pool = AsyncComputeTaskPool::get(); + let load_task = thread_pool.spawn(async move { + let start_time = std::time::Instant::now(); + while start_time.elapsed() < std::time::Duration::from_secs_f32(4.2) + { + // spin + } + 42 // return hydrated project + }); + commands.insert_resource(ProjectLoadTask(load_task)); + } + else if let Some(project_task) = &mut project_task { + if let Some(project_data) = future::block_on(future::poll_once(&mut project_task.0)) { + info!("Project data is: {}", project_data); + app_state.set(AppState::Running).unwrap(); + } + } + } }