Add progress bar for world generation.
Also remove a bunch of spammy logging
This commit is contained in:
parent
1a3b4bb72c
commit
9581a5d206
21 changed files with 221 additions and 89 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2087,6 +2087,7 @@ name = "planet"
|
|||
version = "0.3.0"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"crossbeam-channel",
|
||||
"postcard",
|
||||
"rand",
|
||||
"serde",
|
||||
|
@ -3087,6 +3088,7 @@ version = "0.3.0"
|
|||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_egui",
|
||||
"crossbeam-channel",
|
||||
"futures-lite",
|
||||
"fxhash",
|
||||
"planet",
|
||||
|
|
|
@ -54,4 +54,9 @@ optional = true
|
|||
|
||||
[dependencies.futures-lite]
|
||||
version = "1.12.0"
|
||||
default-features = false
|
||||
default-features = false
|
||||
|
||||
[dependencies.crossbeam-channel]
|
||||
version = "0.5.6"
|
||||
default-features = false
|
||||
features = ["std"]
|
|
@ -26,4 +26,9 @@ features = ["derive"]
|
|||
[dependencies.postcard]
|
||||
version = "1.0.2"
|
||||
default-features = false
|
||||
features = ["use-std"]
|
||||
features = ["use-std"]
|
||||
|
||||
[dependencies.crossbeam-channel]
|
||||
version = "0.5.6"
|
||||
default-features = false
|
||||
features = ["std"]
|
|
@ -4,7 +4,7 @@ pub mod biome;
|
|||
pub use biome::{BiomeStats, BiomeType};
|
||||
pub mod world_manager;
|
||||
pub use world_manager::WorldManager;
|
||||
pub(crate) mod macros;
|
||||
pub mod macros;
|
||||
pub mod math_util;
|
||||
pub mod perlin;
|
||||
pub mod saving;
|
||||
|
|
|
@ -17,6 +17,7 @@ use {
|
|||
prelude::Vec2,
|
||||
utils::{default, HashMap},
|
||||
},
|
||||
crossbeam_channel::Sender,
|
||||
rand::{rngs::StdRng, Rng, SeedableRng},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{
|
||||
|
@ -169,18 +170,25 @@ impl World {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn generate(&mut self) -> Result<(), WorldGenError> {
|
||||
if let Err(err) = self.generate_altitude() {
|
||||
pub fn generate(
|
||||
&mut self,
|
||||
progress_sender: &Sender<(f32, String)>,
|
||||
) -> Result<(), WorldGenError> {
|
||||
send_progress(progress_sender, 0.0, "Generating altitude");
|
||||
if let Err(err) = self.generate_altitude(progress_sender) {
|
||||
return Err(WorldGenError::CartesianError(err));
|
||||
}
|
||||
if let Err(err) = self.generate_rainfall() {
|
||||
send_progress(progress_sender, 0.0, "Generating rainfall");
|
||||
if let Err(err) = self.generate_rainfall(progress_sender) {
|
||||
return Err(WorldGenError::CartesianError(err));
|
||||
}
|
||||
if let Err(err) = self.generate_temperature() {
|
||||
send_progress(progress_sender, 0.0, "Generating temperature");
|
||||
if let Err(err) = self.generate_temperature(progress_sender) {
|
||||
return Err(WorldGenError::CartesianError(err));
|
||||
}
|
||||
|
||||
self.generate_biomes();
|
||||
send_progress(progress_sender, 0.0, "Generating biomes");
|
||||
self.generate_biomes(progress_sender);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -192,8 +200,8 @@ impl World {
|
|||
let height = self.height as f32;
|
||||
|
||||
for i in 0..World::NUM_CONTINENTS {
|
||||
#[cfg(feature = "logging")]
|
||||
info!("Continents {}/{}", i, World::NUM_CONTINENTS);
|
||||
// #[cfg(feature = "logging")]
|
||||
// info!("Continents: {}/{}", i, World::NUM_CONTINENTS);
|
||||
|
||||
self.continent_offsets[i as usize].x = self
|
||||
.rng
|
||||
|
@ -254,7 +262,10 @@ impl World {
|
|||
max_value
|
||||
}
|
||||
|
||||
fn generate_altitude(&mut self) -> Result<(), CartesianError> {
|
||||
fn generate_altitude(
|
||||
&mut self,
|
||||
progress_sender: &Sender<(f32, String)>,
|
||||
) -> Result<(), CartesianError> {
|
||||
info!("Generating altitude");
|
||||
self.generate_continents();
|
||||
|
||||
|
@ -270,13 +281,20 @@ impl World {
|
|||
let offset_4 = World::random_offset_vector(&mut self.rng);
|
||||
let offset_5 = World::random_offset_vector(&mut self.rng);
|
||||
|
||||
for y in 0..self.terrain.len() {
|
||||
#[cfg(feature = "logging")]
|
||||
info!("Altitude: {}/{}", y, self.terrain.len());
|
||||
|
||||
let height = self.terrain.len();
|
||||
for y in 0..height {
|
||||
let alpha = (y as f32 / self.height as f32) * PI;
|
||||
|
||||
for x in 0..self.terrain[y].len() {
|
||||
let width = self.terrain[y].len();
|
||||
let size = height * width;
|
||||
for x in 0..width {
|
||||
let index = y * width + x;
|
||||
send_progress(
|
||||
progress_sender,
|
||||
index as f32 / size as f32,
|
||||
format!("Generating topography: {index}/{size}"),
|
||||
);
|
||||
|
||||
let beta = (x as f32 / self.width as f32) * TAU;
|
||||
|
||||
let value_1 =
|
||||
|
@ -385,20 +403,27 @@ impl World {
|
|||
World::MIN_ALTITUDE + (raw_altitude * World::ALTITUDE_SPAN)
|
||||
}
|
||||
|
||||
fn generate_rainfall(&mut self) -> Result<(), CartesianError> {
|
||||
#[cfg(feature = "logging")]
|
||||
fn generate_rainfall(
|
||||
&mut self,
|
||||
progress_sender: &Sender<(f32, String)>,
|
||||
) -> Result<(), CartesianError> {
|
||||
info!("Generating rainfall");
|
||||
const RADIUS: f32 = 2.0;
|
||||
let offset = World::random_offset_vector(&mut self.rng);
|
||||
|
||||
let height = self.terrain.len();
|
||||
for y in 0..height {
|
||||
#[cfg(feature = "logging")]
|
||||
info!("Rainfall: {}/{}", y, height);
|
||||
let alpha = (y as f32 / self.height as f32) * PI;
|
||||
|
||||
let width = self.terrain[y].len();
|
||||
let size = width * height;
|
||||
for x in 0..width {
|
||||
let index = y * width + x;
|
||||
send_progress(
|
||||
progress_sender,
|
||||
index as f32 / size as f32,
|
||||
format!("Generating rainfall: {index}/{size}"),
|
||||
);
|
||||
let beta = (x as f32 / self.width as f32) * TAU;
|
||||
|
||||
let random_noise =
|
||||
|
@ -459,17 +484,28 @@ impl World {
|
|||
)
|
||||
}
|
||||
|
||||
fn generate_temperature(&mut self) -> Result<(), CartesianError> {
|
||||
#[cfg(feature = "logging")]
|
||||
fn generate_temperature(
|
||||
&mut self,
|
||||
progress_sender: &Sender<(f32, String)>,
|
||||
) -> Result<(), CartesianError> {
|
||||
info!("Generating temperature");
|
||||
let offset = World::random_offset_vector(&mut self.rng);
|
||||
const RADIUS: f32 = 2.0;
|
||||
|
||||
for y in 0..self.terrain.len() {
|
||||
#[cfg(feature = "logging")]
|
||||
info!("Temperature: {}/{}", y, self.terrain.len());
|
||||
let height = self.terrain.len();
|
||||
for y in 0..height {
|
||||
let alpha = (y as f32 / self.height as f32) * PI;
|
||||
for x in 0..self.terrain[y].len() {
|
||||
|
||||
let width = self.terrain[y].len();
|
||||
let size = width * height;
|
||||
for x in 0..width {
|
||||
let index = y * width + x;
|
||||
send_progress(
|
||||
progress_sender,
|
||||
index as f32 / size as f32,
|
||||
format!("Generating temperature: {index}/{size}"),
|
||||
);
|
||||
|
||||
let beta = (x as f32 / self.width as f32) * TAU;
|
||||
|
||||
let random_noise =
|
||||
|
@ -496,6 +532,7 @@ impl World {
|
|||
}
|
||||
}
|
||||
|
||||
info!("Done generating temperature");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -507,12 +544,19 @@ impl World {
|
|||
)
|
||||
}
|
||||
|
||||
fn generate_biomes(&mut self) {
|
||||
fn generate_biomes(&mut self, progress_sender: &Sender<(f32, String)>) {
|
||||
info!("Generating biomes");
|
||||
for y in 0..self.terrain.len() {
|
||||
#[cfg(feature = "logging")]
|
||||
info!("Biomes: {}/{}", y, self.terrain.len());
|
||||
for x in 0..self.terrain[y].len() {
|
||||
let height = self.terrain.len();
|
||||
for y in 0..height {
|
||||
let width = self.terrain[y].len();
|
||||
let size = height * width;
|
||||
for x in 0..width {
|
||||
let index = y * width + x;
|
||||
send_progress(
|
||||
progress_sender,
|
||||
index as f32 / size as f32,
|
||||
format!("Generating biomes: {index}/{size}"),
|
||||
);
|
||||
let cell = &self.terrain[y][x];
|
||||
|
||||
let mut total_presence = 0.0;
|
||||
|
@ -534,6 +578,7 @@ impl World {
|
|||
.collect();
|
||||
}
|
||||
}
|
||||
info!("Done generating biomes");
|
||||
}
|
||||
|
||||
fn biome_presence(&self, cell: &TerrainCell, biome: &BiomeStats) -> f32 {
|
||||
|
@ -767,3 +812,15 @@ impl World {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
fn send_progress<T: Into<String>>(
|
||||
progress_sender: &Sender<(f32, String)>,
|
||||
progress: f32,
|
||||
progress_text: T,
|
||||
) {
|
||||
if let Err(_) = progress_sender.try_send((progress, progress_text.into())) {
|
||||
// Quietly ignore the error, it's not critical, and logging is slow.
|
||||
|
||||
// debug!("Failed to send world generation progress. {err}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ use {
|
|||
tasks::{AsyncComputeTaskPool, Task},
|
||||
utils::default,
|
||||
},
|
||||
crossbeam_channel::Sender,
|
||||
rand::random,
|
||||
std::{
|
||||
error::Error,
|
||||
|
@ -99,7 +100,6 @@ impl WorldManager {
|
|||
return Err(SaveError::MissingWorld);
|
||||
};
|
||||
|
||||
|
||||
let serialized = match postcard::to_stdvec(world) {
|
||||
Ok(serialized) => serialized,
|
||||
Err(err) => {
|
||||
|
@ -124,7 +124,7 @@ impl WorldManager {
|
|||
if let Err(err) = file.read_to_end(&mut buf) {
|
||||
return Err(LoadError::MissingSave(err));
|
||||
};
|
||||
|
||||
|
||||
match postcard::from_bytes(buf.as_slice()) {
|
||||
Ok(world) => {
|
||||
self.world = Some(world);
|
||||
|
@ -139,11 +139,15 @@ impl WorldManager {
|
|||
self.world.as_ref()
|
||||
}
|
||||
|
||||
pub fn set_world(&mut self, world: World) {
|
||||
pub fn set_world(&mut self, world: World) {
|
||||
self.world = Some(world);
|
||||
}
|
||||
|
||||
pub fn new_world_async(&mut self, seed: Option<u32>) -> Task<Result<World, WorldGenError>> {
|
||||
pub fn new_world_async(
|
||||
&mut self,
|
||||
seed: Option<u32>,
|
||||
progress_sender: Sender<(f32, String)>,
|
||||
) -> Task<Result<World, WorldGenError>> {
|
||||
AsyncComputeTaskPool::get().spawn(async move {
|
||||
let seed = seed.unwrap_or_else(random);
|
||||
let mut new_world = World::async_new(
|
||||
|
@ -151,7 +155,18 @@ impl WorldManager {
|
|||
WorldManager::NEW_WORLD_HEIGHT,
|
||||
seed,
|
||||
);
|
||||
match new_world.generate() {
|
||||
if let Err(_) =
|
||||
progress_sender.try_send((0.0, String::from("Generating new world...")))
|
||||
{
|
||||
// Quietly ignore. It's not critical and logging is slow.
|
||||
}
|
||||
let result = new_world.generate(&progress_sender);
|
||||
if let Err(_) =
|
||||
progress_sender.try_send((1.0, String::from("Done generating world!")))
|
||||
{
|
||||
// Quietly ignore. See above
|
||||
}
|
||||
match result {
|
||||
Ok(()) => Ok(new_world),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
pub(crate) mod widget;
|
||||
pub(crate) use widget::*;
|
||||
pub(crate) mod window;
|
||||
pub(crate) use window::*;
|
||||
pub mod widget;
|
||||
pub use widget::*;
|
||||
pub mod window;
|
||||
pub use window::*;
|
||||
|
||||
pub(crate) mod widgets;
|
||||
pub(crate) mod windows;
|
||||
pub mod widgets;
|
||||
pub mod windows;
|
||||
|
||||
use crate::gui::{open_window, WidgetId, WidgetSystem};
|
||||
|
|
|
@ -14,11 +14,11 @@ use {
|
|||
std::hash::Hasher,
|
||||
};
|
||||
|
||||
pub(crate) trait WidgetSystem: SystemParam {
|
||||
pub trait WidgetSystem: SystemParam {
|
||||
fn render(world: &mut World, state: &mut SystemState<Self>, ui: &mut Ui, id: WidgetId);
|
||||
}
|
||||
|
||||
pub(crate) fn widget<S: 'static + WidgetSystem>(world: &mut World, ui: &mut Ui, id: WidgetId) {
|
||||
pub fn widget<S: 'static + WidgetSystem>(world: &mut World, ui: &mut Ui, id: WidgetId) {
|
||||
// We need to cache `SystemState` to allow for a system's locally tracked state
|
||||
if !world.contains_resource::<StateInstances<S>>() {
|
||||
// Note, this message should only appear once! If you see it twice in the logs,
|
||||
|
@ -51,10 +51,10 @@ struct StateInstances<T: WidgetSystem + 'static> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct WidgetId(pub(crate) u64);
|
||||
pub struct WidgetId(pub u64);
|
||||
impl WidgetId {
|
||||
#[must_use]
|
||||
pub(crate) fn new(name: &str) -> Self {
|
||||
pub fn new(name: &str) -> Self {
|
||||
let bytes = name.as_bytes();
|
||||
let mut hasher = FxHasher32::default();
|
||||
hasher.write(bytes);
|
||||
|
@ -62,7 +62,7 @@ impl WidgetId {
|
|||
}
|
||||
|
||||
// #[must_use]
|
||||
// pub(crate) fn with(&self, name: &str) -> Self {
|
||||
// pub fn with(&self, name: &str) -> Self {
|
||||
// Self::new(&format!("{}{name}", self.0))
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
mod toolbar;
|
||||
pub(crate) use toolbar::ToolbarWidget;
|
||||
pub use toolbar::ToolbarWidget;
|
||||
|
|
|
@ -7,7 +7,7 @@ use {
|
|||
WidgetSystem,
|
||||
},
|
||||
macros::iterable_enum,
|
||||
resources::{GenerateWorldTask, OpenedWindows},
|
||||
resources::{GenerateWorldProgressChannel, GenerateWorldTask, OpenedWindows},
|
||||
},
|
||||
bevy::{
|
||||
ecs::{
|
||||
|
@ -34,11 +34,13 @@ impl ToolbarButton {
|
|||
world.resource_scope(|world, mut world_manager: Mut<WorldManager>| {
|
||||
match self {
|
||||
ToolbarButton::GenerateWorld => {
|
||||
let progress_sender = world.resource::<GenerateWorldProgressChannel>().sender();
|
||||
let generate_world_task = &mut world.resource_mut::<GenerateWorldTask>();
|
||||
if generate_world_task.0.is_some() {
|
||||
debug!("Already generating new world")
|
||||
} else {
|
||||
generate_world_task.0 = Some(world_manager.new_world_async(None))
|
||||
generate_world_task.0 =
|
||||
Some(world_manager.new_world_async(None, progress_sender))
|
||||
}
|
||||
},
|
||||
ToolbarButton::SaveLoad => {
|
||||
|
@ -87,7 +89,7 @@ impl From<&ToolbarButton> for String {
|
|||
}
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub(crate) struct ToolbarWidget<'w, 's> {
|
||||
pub struct ToolbarWidget<'w, 's> {
|
||||
#[system_param(ignore)]
|
||||
_phantom: PhantomData<(&'w (), &'s ())>,
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@ use {
|
|||
std::hash::Hasher,
|
||||
};
|
||||
|
||||
pub(crate) trait WindowSystem: SystemParam {
|
||||
pub trait WindowSystem: SystemParam {
|
||||
fn draw_contents(world: &mut World, state: &mut SystemState<Self>, ui: &mut Ui);
|
||||
fn name() -> &'static str;
|
||||
fn resizable() -> bool;
|
||||
}
|
||||
|
||||
pub(crate) fn render_windows(world: &mut World, ctx: &Context) {
|
||||
pub fn render_windows(world: &mut World, ctx: &Context) {
|
||||
// TODO: Windows are hard-coded here instead of being iterable, and allows
|
||||
// creating new windows that are never rendered.
|
||||
// Is that good enough?
|
||||
|
@ -32,10 +32,10 @@ pub(crate) fn render_windows(world: &mut World, ctx: &Context) {
|
|||
window::<windows::SaveLoad>(world, ctx);
|
||||
}
|
||||
|
||||
pub(crate) fn open_window<S: 'static + WindowSystem>(windows: &mut OpenedWindows) {
|
||||
pub fn open_window<S: 'static + WindowSystem>(windows: &mut OpenedWindows) {
|
||||
windows.open(S::name().into());
|
||||
}
|
||||
pub(crate) fn close_window<S: 'static + WindowSystem>(windows: &mut OpenedWindows) {
|
||||
pub fn close_window<S: 'static + WindowSystem>(windows: &mut OpenedWindows) {
|
||||
windows.close(&S::name().into());
|
||||
}
|
||||
|
||||
|
@ -87,10 +87,10 @@ struct StateInstances<T: WindowSystem + 'static> {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct WindowId(pub(crate) u64);
|
||||
pub struct WindowId(pub u64);
|
||||
impl WindowId {
|
||||
#[must_use]
|
||||
pub(crate) fn new(name: &str) -> Self {
|
||||
pub fn new(name: &str) -> Self {
|
||||
let bytes = name.as_bytes();
|
||||
let mut hasher = FxHasher32::default();
|
||||
hasher.write(bytes);
|
||||
|
@ -98,7 +98,7 @@ impl WindowId {
|
|||
}
|
||||
|
||||
// #[must_use]
|
||||
// pub(crate) fn with(&self, name: &str) -> Self {
|
||||
// pub fn with(&self, name: &str) -> Self {
|
||||
// Self::new(&format!("{}{name}", self.0))
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
mod tile_info;
|
||||
pub(crate) use tile_info::TileInfo;
|
||||
pub use tile_info::TileInfo;
|
||||
mod world_view_selection;
|
||||
pub(crate) use world_view_selection::WorldViewSelection;
|
||||
pub use world_view_selection::WorldViewSelection;
|
||||
mod world_overlay_selection;
|
||||
pub(crate) use world_overlay_selection::WorldOverlaySelection;
|
||||
pub use world_overlay_selection::WorldOverlaySelection;
|
||||
mod save_load;
|
||||
pub(crate) use save_load::SaveLoad;
|
||||
pub use save_load::SaveLoad;
|
||||
|
|
|
@ -14,7 +14,7 @@ use {
|
|||
};
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub(crate) struct SaveLoad<'w, 's> {
|
||||
pub struct SaveLoad<'w, 's> {
|
||||
pub file_name: Local<'s, String>,
|
||||
#[system_param(ignore)]
|
||||
_phantom: PhantomData<(&'w (), &'s ())>,
|
||||
|
|
|
@ -10,7 +10,7 @@ use {
|
|||
};
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub(crate) struct TileInfo<'w, 's> {
|
||||
pub struct TileInfo<'w, 's> {
|
||||
#[system_param(ignore)]
|
||||
_phantom: PhantomData<(&'w (), &'s ())>,
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use {
|
|||
};
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub(crate) struct WorldOverlaySelection<'w, 's> {
|
||||
pub struct WorldOverlaySelection<'w, 's> {
|
||||
#[system_param(ignore)]
|
||||
_phantom: PhantomData<(&'w (), &'s ())>,
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use {
|
|||
};
|
||||
|
||||
#[derive(SystemParam)]
|
||||
pub(crate) struct WorldViewSelection<'w, 's> {
|
||||
pub struct WorldViewSelection<'w, 's> {
|
||||
#[system_param(ignore)]
|
||||
_phantom: PhantomData<(&'w (), &'s ())>,
|
||||
}
|
||||
|
|
41
src/main.rs
41
src/main.rs
|
@ -3,23 +3,24 @@
|
|||
use {
|
||||
crate::resources::GenerateWorldTask,
|
||||
futures_lite::future::{block_on, poll_once},
|
||||
resources::GenerateWorldProgressChannel,
|
||||
};
|
||||
|
||||
pub(crate) mod components;
|
||||
pub mod components;
|
||||
#[cfg(feature = "render")]
|
||||
pub(crate) mod gui;
|
||||
pub(crate) mod macros;
|
||||
pub mod gui;
|
||||
pub mod macros;
|
||||
#[cfg(feature = "render")]
|
||||
pub(crate) mod planet_renderer;
|
||||
pub(crate) mod plugins;
|
||||
pub(crate) mod resources;
|
||||
pub mod planet_renderer;
|
||||
pub mod plugins;
|
||||
pub mod resources;
|
||||
|
||||
use {bevy::prelude::*, planet::WorldManager, plugins::WorldPlugins};
|
||||
#[cfg(feature = "render")]
|
||||
use {
|
||||
bevy::render::camera::RenderTarget,
|
||||
bevy_egui::{
|
||||
egui::{FontData, FontDefinitions, FontFamily},
|
||||
egui::{FontData, FontDefinitions, FontFamily, ProgressBar},
|
||||
EguiContext,
|
||||
},
|
||||
gui::{render_windows, widget, widgets::ToolbarWidget, window::open_window, windows::TileInfo},
|
||||
|
@ -73,6 +74,9 @@ fn handle_generate_world_task(
|
|||
mut generate_world_task: ResMut<GenerateWorldTask>,
|
||||
mut world_manager: ResMut<WorldManager>,
|
||||
#[cfg(feature = "render")] mut should_redraw: ResMut<ShouldRedraw>,
|
||||
#[cfg(feature = "render")] mut egui_ctx: ResMut<'_, EguiContext>,
|
||||
#[cfg(feature = "render")] progress_channel: Res<'_, GenerateWorldProgressChannel>,
|
||||
#[cfg(feature = "render")] mut progress: Local<(f32, String)>,
|
||||
) {
|
||||
if let Some(task) = &mut generate_world_task.0 {
|
||||
if task.is_finished() {
|
||||
|
@ -92,8 +96,24 @@ fn handle_generate_world_task(
|
|||
}
|
||||
}
|
||||
generate_world_task.0 = None;
|
||||
#[cfg(feature = "render")]
|
||||
{
|
||||
*progress = (0.0, String::from("Generating world..."));
|
||||
}
|
||||
} else {
|
||||
debug!("Still generating world")
|
||||
debug!("Still generating world");
|
||||
|
||||
#[cfg(feature = "render")]
|
||||
{
|
||||
if let Ok(new_progress) = progress_channel.receiver().try_recv() {
|
||||
*progress = new_progress;
|
||||
}
|
||||
_ = bevy_egui::egui::TopBottomPanel::bottom("Generating World ProgressBar")
|
||||
.default_height(8.0)
|
||||
.show(egui_ctx.ctx_mut(), |ui| {
|
||||
ui.add(ProgressBar::new(progress.0).text(progress.1.as_str()));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,9 +313,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
|
||||
app.insert_resource(WorldManager::new())
|
||||
.insert_resource(GenerateWorldTask(
|
||||
/* Some(manager.new_world_async(Some(0))) */ None,
|
||||
))
|
||||
.insert_resource(GenerateWorldProgressChannel::new())
|
||||
.insert_resource(GenerateWorldTask(None))
|
||||
.add_system(handle_generate_world_task)
|
||||
.run();
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ fn coastline_color(world: &World, cell: &TerrainCell) -> Color {
|
|||
COASTLINE_PALETTE[0]
|
||||
}
|
||||
}
|
||||
pub(crate) trait WorldRenderer {
|
||||
pub trait WorldRenderer {
|
||||
fn map_color_bytes(&self, render_settings: &WorldRenderSettings) -> Vec<u8>;
|
||||
fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color;
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
pub(crate) mod world_plugins;
|
||||
pub(crate) use world_plugins::WorldPlugins;
|
||||
pub mod world_plugins;
|
||||
pub use world_plugins::WorldPlugins;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
pub(crate) struct WorldPlugins;
|
||||
pub struct WorldPlugins;
|
||||
|
||||
#[cfg(not(feature = "render"))]
|
||||
use bevy::app::ScheduleRunnerPlugin;
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
use {crate::gui::WindowId, bevy::utils::HashSet, std::fmt::Display};
|
||||
use {
|
||||
bevy::{prelude::Resource, tasks::Task},
|
||||
crossbeam_channel::{bounded, Receiver, Sender},
|
||||
planet::{World, WorldGenError},
|
||||
};
|
||||
|
||||
#[cfg(feature = "render")]
|
||||
#[derive(Default, Debug, Resource)]
|
||||
pub(crate) struct CursorMapPosition {
|
||||
pub(crate) x: i32,
|
||||
pub(crate) y: i32,
|
||||
pub struct CursorMapPosition {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
}
|
||||
#[cfg(feature = "render")]
|
||||
impl Display for CursorMapPosition {
|
||||
|
@ -20,27 +21,53 @@ impl Display for CursorMapPosition {
|
|||
|
||||
#[cfg(feature = "render")]
|
||||
#[derive(Resource, Default)]
|
||||
pub(crate) struct ShouldRedraw(pub(crate) bool);
|
||||
pub struct ShouldRedraw(pub bool);
|
||||
#[cfg(feature = "render")]
|
||||
#[derive(Default, Resource)]
|
||||
pub(crate) struct OpenedWindows(HashSet<WindowId>);
|
||||
pub struct OpenedWindows(HashSet<WindowId>);
|
||||
|
||||
#[cfg(feature = "render")]
|
||||
impl OpenedWindows {
|
||||
pub(crate) fn open(&mut self, id: WindowId) {
|
||||
pub fn open(&mut self, id: WindowId) {
|
||||
// Ignore opening already opened windows
|
||||
_ = self.0.insert(id);
|
||||
}
|
||||
|
||||
pub(crate) fn close(&mut self, id: &WindowId) {
|
||||
pub fn close(&mut self, id: &WindowId) {
|
||||
// Ignore closing already closed windows
|
||||
_ = self.0.remove(id);
|
||||
}
|
||||
|
||||
pub(crate) fn is_open(&self, id: &WindowId) -> bool {
|
||||
pub fn is_open(&self, id: &WindowId) -> bool {
|
||||
self.0.contains(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource)]
|
||||
pub struct GenerateWorldProgressChannel(Sender<(f32, String)>, Receiver<(f32, String)>);
|
||||
|
||||
impl GenerateWorldProgressChannel {
|
||||
pub fn new() -> Self {
|
||||
bounded(1).into()
|
||||
}
|
||||
|
||||
pub fn sender(&self) -> Sender<(f32, String)> {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
pub fn receiver(&self) -> &Receiver<(f32, String)> {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
impl Default for GenerateWorldProgressChannel {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl From<(Sender<(f32, String)>, Receiver<(f32, String)>)> for GenerateWorldProgressChannel {
|
||||
fn from(value: (Sender<(f32, String)>, Receiver<(f32, String)>)) -> Self {
|
||||
Self(value.0, value.1)
|
||||
}
|
||||
}
|
||||
#[derive(Default, Resource)]
|
||||
pub struct GenerateWorldTask(pub Option<Task<Result<World, WorldGenError>>>);
|
||||
|
|
Loading…
Reference in a new issue