Skip to content

Commit

Permalink
Implement preloading shaders on app start
Browse files Browse the repository at this point in the history
  • Loading branch information
vladbat00 committed Jan 23, 2023
1 parent 9179769 commit e4d574a
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 46 deletions.
2 changes: 1 addition & 1 deletion bins/web_client/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
margin-left: -200px;

border: 1px solid #3c3c3c;
border-radius: 10px;
border-radius: 5px;
background-color: #1b1b1b;
box-shadow: 0 0 20px 20px rgba(0, 0, 0, 0.25);
overflow: hidden;
Expand Down
85 changes: 85 additions & 0 deletions libs/client_lib/src/init_app_systems.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use crate::{
components::{CameraPivotDirection, CameraPivotTag},
MainCameraEntity, MainCameraPivotEntity,
};
use bevy::{
core_pipeline::core_3d::Camera3dBundle,
ecs::{
entity::Entity,
system::{Commands, Local},
},
hierarchy::BuildChildren,
log,
math::{Vec2, Vec3},
pbr::{PbrBundle, PointLight, PointLightBundle},
transform::components::{GlobalTransform, Transform},
};
use iyes_loopless::state::NextState;
use mr_shared_lib::{client::assets::MuddleAssets, AppState};

/// This system is needed for the web version. As assets loading is blocking
/// there, we need to trigger loading shaders before we join a game.
pub fn load_shaders_system(
mut commands: Commands,
assets: MuddleAssets,
mut frames_skipped: Local<u8>,
mut entities_to_clean_up: Local<Vec<Entity>>,
) {
// This lets Egui to fully initialise and finish loading its shaders. <3
*frames_skipped += 1;
if *frames_skipped < 3 {
return;
}

if !entities_to_clean_up.is_empty() {
for entity in std::mem::take(&mut *entities_to_clean_up) {
commands.entity(entity).despawn();
}
log::info!("Changing the app state to {:?}", AppState::MainMenu);
commands.insert_resource(NextState(AppState::MainMenu));
return;
}

log::info!("Starting to load the shaders");
entities_to_clean_up.push(
commands
.spawn(PbrBundle {
mesh: assets.meshes.control_point.clone(),
material: assets.materials.player.clone(),
..Default::default()
})
.id(),
);
}

pub fn basic_scene_system(mut commands: Commands) {
// Add entities to the scene.
commands.spawn(PointLightBundle {
point_light: PointLight {
range: 256.0,
intensity: 1280000.0,
..Default::default()
},
transform: Transform::from_translation(Vec3::new(-64.0, -92.0, 144.0)),
..Default::default()
});
// Camera.
let main_camera_entity = commands
.spawn(Camera3dBundle {
transform: Transform::from_translation(Vec3::new(-3.0, -14.0, 14.0))
.looking_at(Vec3::default(), Vec3::Z),
..Default::default()
})
.insert(bevy_mod_picking::PickingCameraBundle::default())
.id();
let main_camera_pivot_entity = commands
.spawn_empty()
.insert(CameraPivotTag)
.insert(CameraPivotDirection(Vec2::ZERO))
.insert(Transform::IDENTITY)
.insert(GlobalTransform::IDENTITY)
.add_child(main_camera_entity)
.id();
commands.insert_resource(MainCameraPivotEntity(main_camera_pivot_entity));
commands.insert_resource(MainCameraEntity(main_camera_entity));
}
61 changes: 17 additions & 44 deletions libs/client_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ pub use net::DEFAULT_SERVER_PORT;

use crate::{
camera::{move_free_camera_pivot_system, reattach_camera_system},
components::{CameraPivotDirection, CameraPivotTag},
config_storage::OfflineAuthConfig,
game_events::process_scheduled_spawns_system,
init_app_systems::load_shaders_system,
input::{LevelObjectRequestsQueue, MouseRay, MouseWorldPosition, PlayerRequestsQueue},
net::{
auth::read_offline_auth_config_system, fill_actual_frames_ahead_system,
Expand All @@ -34,13 +34,8 @@ use bevy::{
schedule::{IntoSystemDescriptor, ShouldRun, SystemStage},
system::{Commands, IntoSystem, Local, Res, ResMut, Resource, SystemParam},
},
hierarchy::BuildChildren,
log,
math::{Vec2, Vec3},
pbr::{PointLight, PointLightBundle},
prelude::Camera3dBundle,
time::Time,
transform::components::{GlobalTransform, Transform},
utils::{HashMap, Instant},
};
use bevy_egui::EguiPlugin;
Expand All @@ -63,6 +58,7 @@ mod components;
mod config_storage;
mod game_events;
mod helpers;
mod init_app_systems;
mod input;
mod net;
mod ui;
Expand All @@ -77,7 +73,7 @@ pub struct MuddleClientPlugin;
impl Plugin for MuddleClientPlugin {
fn build(&self, app: &mut App) {
let input_stage = SystemStage::single_threaded()
.with_system(maintain_connection_system)
.with_system(maintain_connection_system.run_not_in_state(AppState::Loading))
// Processing network events should happen before tracking input:
// we rely on resetting current's player inputs on each delta update message (event).
.with_system(process_network_events_system.after(maintain_connection_system))
Expand Down Expand Up @@ -107,8 +103,10 @@ impl Plugin for MuddleClientPlugin {
.add_event::<EditedObjectUpdate>()
// Startup systems.
.add_startup_system(init_matchmaker_connection_system)
.add_startup_system(basic_scene_system)
.add_startup_system(init_app_systems::basic_scene_system)
.add_startup_system(read_offline_auth_config_system)
// Loading the app.
.add_system(load_shaders_system.run_in_state(AppState::Loading))
// Game.
.add_plugin(MuddleSharedPlugin::new(
IntoSystem::into_system(net_adaptive_run_criteria),
Expand All @@ -124,21 +122,28 @@ impl Plugin for MuddleClientPlugin {
.add_system(ui::debug_ui::update_debug_visibility_system)
.add_system(ui::debug_ui::debug_ui_system)
.add_system(ui::debug_ui::profiler_ui_system)
.add_system(ui::overlay_ui::connection_status_overlay_system)
.add_system(ui::overlay_ui::app_loading_ui.run_in_state(AppState::Loading))
.add_system(
ui::overlay_ui::connection_status_overlay_system
.run_not_in_state(AppState::Loading),
)
.add_system(ui::debug_ui::inspect_object_system)
.add_system(ui::player_ui::leaderboard_ui_system)
.add_system(ui::player_ui::help_ui_system)
.add_system(
ui::player_ui::leaderboard_ui_system.run_not_in_state(GameSessionState::Loading),
)
.add_system(ui::player_ui::help_ui_system.run_not_in_state(GameSessionState::Loading))
.add_startup_system(ui::main_menu_ui::init_menu_auth_state_system)
.add_system_set(
ui::main_menu_ui::process_io_messages_system_set().label("process_io_messages"),
)
.add_system(
ui::main_menu_ui::main_menu_ui_system
.run_in_state(AppState::MainMenu)
.run_if(matchmaker_is_initialised)
.run_if_not(has_server_to_connect)
.after("process_io_messages"),
)
// Not only Egui for builder mode.
// Builder mode systems.
.add_system_set(ui::builder_ui::builder_system_set().label("builder_system_set"))
// Add to the system set above after fixing https://github.com/mvlabat/muddle-run/issues/46.
.add_system(process_control_points_input_system.after("builder_system_set"))
Expand Down Expand Up @@ -336,38 +341,6 @@ fn pause_simulation_system(
}
}

fn basic_scene_system(mut commands: Commands) {
// Add entities to the scene.
commands.spawn(PointLightBundle {
point_light: PointLight {
range: 256.0,
intensity: 1280000.0,
..Default::default()
},
transform: Transform::from_translation(Vec3::new(-64.0, -92.0, 144.0)),
..Default::default()
});
// Camera.
let main_camera_entity = commands
.spawn(Camera3dBundle {
transform: Transform::from_translation(Vec3::new(-3.0, -14.0, 14.0))
.looking_at(Vec3::default(), Vec3::Z),
..Default::default()
})
.insert(bevy_mod_picking::PickingCameraBundle::default())
.id();
let main_camera_pivot_entity = commands
.spawn_empty()
.insert(CameraPivotTag)
.insert(CameraPivotDirection(Vec2::ZERO))
.insert(Transform::IDENTITY)
.insert(GlobalTransform::IDENTITY)
.add_child(main_camera_entity)
.id();
commands.insert_resource(MainCameraPivotEntity(main_camera_pivot_entity));
commands.insert_resource(MainCameraEntity(main_camera_entity));
}

#[derive(SystemParam)]
pub struct ControlTickingSpeedParams<'w, 's> {
current_ticks_per_second: ResMut<'w, GameTicksPerSecond>,
Expand Down
36 changes: 35 additions & 1 deletion libs/client_lib/src/ui/overlay_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,40 @@ use bevy::ecs::system::{Res, ResMut};
use bevy_egui::{egui, EguiContext};
use mr_shared_lib::net::{ConnectionState, ConnectionStatus};

pub fn app_loading_ui(mut egui_context: ResMut<EguiContext>) {
let window_width = 400.0;
let window_height = 100.0;

egui::CentralPanel::default()
.frame(egui::Frame::none().fill(egui::Color32::from_rgb(47, 47, 47)))
.show(egui_context.ctx_mut(), |ui| {
ui.style_mut().spacing.window_margin = egui::style::Margin::same(0.0);
egui::Window::new("app loading ui")
.frame(egui::Frame::window(ui.style()))
.title_bar(false)
.collapsible(false)
.resizable(false)
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
.fixed_size(egui::Vec2::new(window_width, window_height))
.show(ui.ctx(), |ui| {
let rounding = ui.style().visuals.window_rounding;
let fill = egui::Color32::from_rgb(23, 98, 3);
let stroke = egui::Stroke::new(1.0, egui::Color32::from_rgb(60, 60, 60));

ui.painter().add(egui::Shape::Rect(egui::epaint::RectShape {
rect: ui.max_rect(),
rounding,
fill,
stroke,
}));
ui.centered_and_justified(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Heading);
ui.label("Loading shaders...");
});
});
});
}

pub fn connection_status_overlay_system(
mut egui_context: ResMut<EguiContext>,
connection_state: Res<ConnectionState>,
Expand All @@ -18,7 +52,7 @@ pub fn connection_status_overlay_system(
return;
}

let window_width = 200.0;
let window_width = 400.0;
let window_height = 100.0;

let ctx = egui_context.ctx_mut();
Expand Down

0 comments on commit e4d574a

Please sign in to comment.