use bevy::prelude::*;
use bevy_mod_scripting::lua::*;
use bevy_mod_scripting::prelude::*;
use bevy_mod_scripting_core::pipeline::ScriptPipelineState;
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
enum GameState {
#[default]
ScriptLoading,
Running,
}
pub fn initialize_script_loading(
asset_server: ResMut<AssetServer>,
mut commands: Commands,
) {
for _ in 0..1000 {
let script = ScriptAsset::new(
"
function on_script_loaded()
end
"
.to_string(),
);
let handle = asset_server.add(script);
commands.spawn(ScriptComponent(vec![handle]));
}
}
#[derive(Component)]
struct LoadingBarFill;
#[derive(Component)]
struct ScriptNameText;
#[derive(Component)]
struct PercentageText;
fn setup_loading_ui(mut commands: Commands) {
commands.spawn(Camera2d);
commands
.spawn((
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
BackgroundColor(Color::NONE),
))
.with_children(|parent| {
parent
.spawn((
Node {
width: Val::Px(400.0),
height: Val::Px(120.0),
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
row_gap: Val::Px(10.0),
..default()
},
BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.3)),
))
.with_children(|column| {
column.spawn((
Text::new("Loading: (none)"),
TextFont {
font_size: 24.0,
..default()
},
TextColor(Color::WHITE),
ScriptNameText,
));
column
.spawn((
Node {
width: Val::Px(300.0),
height: Val::Px(24.0),
justify_content: JustifyContent::FlexStart,
align_items: AlignItems::Center,
..default()
},
BackgroundColor(Color::darker(&Color::WHITE, 0.5)),
))
.with_children(|bar_bg| {
bar_bg.spawn((
Node {
width: Val::Percent(0.0), height: Val::Percent(100.0),
..default()
},
BackgroundColor(Color::linear_rgb(0.0, 1.0, 0.0)),
LoadingBarFill,
));
});
column.spawn((
Text::new("0%"),
TextFont {
font_size: 20.0,
..default()
},
TextColor(Color::WHITE),
PercentageText,
));
});
});
}
fn update_loading_ui(
pipeline_state: ScriptPipelineState<LuaScriptingPlugin>,
mut fill_query: Query<&mut Node, With<LoadingBarFill>>,
mut name_query: Query<&mut Text, (With<ScriptNameText>, Without<PercentageText>)>,
mut percent_query: Query<&mut Text, (With<PercentageText>, Without<ScriptNameText>)>,
mut next_state: ResMut<NextState<GameState>>,
) {
let (progress, loaded, total) = pipeline_state.progress();
let current_script = pipeline_state
.currently_loading_script()
.and_then(|handle| handle.path().cloned())
.map(|p| p.to_string())
.unwrap_or(String::from("script"));
if let Ok(mut node) = fill_query.single_mut() {
node.width = Val::Percent(progress);
}
if let Ok(mut text) = name_query.single_mut() {
*text = Text::new(format!("Loading: {current_script}"));
}
if let Ok(mut text) = percent_query.single_mut() {
*text = Text::new(format!("{progress:.0}% ({loaded}/{total})"));
}
if pipeline_state.processing_batch_completed() && loaded > 0 {
next_state.set(GameState::Running)
}
}
fn set_loading_ui_completed(
mut name_query: Query<&mut Text, (With<ScriptNameText>, Without<PercentageText>)>,
) {
if let Ok(mut text) = name_query.single_mut() {
*text = Text::new("Loaded all scripts!".to_string());
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(BMSPlugin)
.init_state::<GameState>()
.add_systems(Startup, (initialize_script_loading, setup_loading_ui))
.add_systems(
Update,
update_loading_ui.run_if(in_state(GameState::ScriptLoading)),
)
.add_systems(OnEnter(GameState::Running), set_loading_ui_completed)
.run();
}