Don't generate world on startup

This commit is contained in:
Tobias Berger 2022-11-15 10:57:21 +01:00
parent f65f29e6b0
commit b9e402ecf9
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
6 changed files with 73 additions and 78 deletions

View file

@ -162,28 +162,10 @@ impl WorldManager {
self.world.as_ref() self.world.as_ref()
} }
#[must_use]
pub fn world(&self) -> &World {
assert!(self.world.is_some(), "No world.");
self.get_world().unwrap()
}
pub fn set_world(&mut self, world: World) { pub fn set_world(&mut self, world: World) {
self.world = Some(world); self.world = Some(world);
} }
pub fn new_world(&mut self, seed: Option<u32>) -> Result<&World, WorldGenError> {
let seed = seed.unwrap_or_else(random);
let mut new_world = World::new(
WorldManager::NEW_WORLD_WIDTH,
WorldManager::NEW_WORLD_HEIGHT,
seed,
);
new_world.generate()?;
self.world = Some(new_world);
Ok(self.get_world().unwrap())
}
pub fn new_world_async(&mut self, seed: Option<u32>) -> Task<Result<World, WorldGenError>> { pub fn new_world_async(&mut self, seed: Option<u32>) -> Task<Result<World, WorldGenError>> {
AsyncComputeTaskPool::get().spawn(async move { AsyncComputeTaskPool::get().spawn(async move {
let seed = seed.unwrap_or_else(random); let seed = seed.unwrap_or_else(random);

View file

@ -25,11 +25,14 @@ impl WindowSystem for TileInfo<'_, '_> {
let cursor_y = cursor_position.y; let cursor_y = cursor_position.y;
let cursor_x = cursor_position.x; let cursor_x = cursor_position.x;
let world_manager = world.resource::<WorldManager>(); let Some(world) = world.resource::<WorldManager>().get_world() else {
ui.label("No world.");
return;
};
if cursor_x >= 0 if cursor_x >= 0
&& cursor_x < world_manager.world().width.try_into().unwrap() && cursor_x < world.width.try_into().unwrap()
&& cursor_y >= 0 && cursor_y >= 0
&& cursor_y < world_manager.world().height.try_into().unwrap() && cursor_y < world.height.try_into().unwrap()
{ {
let TerrainCell { let TerrainCell {
altitude, altitude,
@ -38,7 +41,7 @@ impl WindowSystem for TileInfo<'_, '_> {
biome_presences, biome_presences,
x, x,
y, y,
} = &world_manager.world().terrain[cursor_y as usize][cursor_x as usize]; } = &world.terrain[cursor_y as usize][cursor_x as usize];
_ = ui.label("Coordinates"); _ = ui.label("Coordinates");
_ = ui.label(format!("{x}:{y}")); _ = ui.label(format!("{x}:{y}"));

View file

@ -42,6 +42,9 @@ fn update_cursor_map_position(
windows: Res<'_, Windows>, windows: Res<'_, Windows>,
world_manager: Res<'_, WorldManager>, world_manager: Res<'_, WorldManager>,
) { ) {
let Some(world) = world_manager.get_world() else {
return
};
let (camera, transform) = transform.single(); let (camera, transform) = transform.single();
let window = match camera.target { let window = match camera.target {
@ -61,7 +64,6 @@ fn update_cursor_map_position(
let world_position = let world_position =
ndc_to_world.project_point3(ndc.extend(-1.0)).truncate() / WORLD_SCALE as f32; ndc_to_world.project_point3(ndc.extend(-1.0)).truncate() / WORLD_SCALE as f32;
let world = world_manager.world();
cursor_map_position.x = world.width as i32 / 2 + f32::ceil(world_position.x) as i32 - 1; cursor_map_position.x = world.width as i32 / 2 + f32::ceil(world_position.x) as i32 - 1;
cursor_map_position.y = world.height as i32 / 2 + f32::ceil(world_position.y) as i32 - 1; cursor_map_position.y = world.height as i32 / 2 + f32::ceil(world_position.y) as i32 - 1;
} }
@ -74,7 +76,7 @@ fn handle_generate_world_task(
) { ) {
if let Some(task) = &mut generate_world_task.0 { if let Some(task) = &mut generate_world_task.0 {
if task.is_finished() { if task.is_finished() {
debug!("Done"); debug!("Done generating world");
if let Some(result) = block_on(poll_once(task)) { if let Some(result) = block_on(poll_once(task)) {
match result { match result {
Ok(world) => { Ok(world) => {
@ -82,6 +84,8 @@ fn handle_generate_world_task(
#[cfg(feature = "render")] #[cfg(feature = "render")]
{ {
should_redraw.0 = true; should_redraw.0 = true;
#[cfg(feature = "logging")]
debug!("Requesting map redraw");
} }
}, },
Err(err) => error!("{err:#?}"), Err(err) => error!("{err:#?}"),
@ -89,7 +93,7 @@ fn handle_generate_world_task(
} }
generate_world_task.0 = None; generate_world_task.0 = None;
} else { } else {
debug!("Working") debug!("Still generating world")
} }
} }
} }
@ -97,13 +101,11 @@ fn handle_generate_world_task(
#[cfg(feature = "render")] #[cfg(feature = "render")]
fn generate_graphics( fn generate_graphics(
mut commands: Commands<'_, '_>, mut commands: Commands<'_, '_>,
world_manager: ResMut<'_, WorldManager>,
images: ResMut<'_, Assets<Image>>, images: ResMut<'_, Assets<Image>>,
egui_context: ResMut<'_, EguiContext>, egui_context: ResMut<'_, EguiContext>,
render_settings: ResMut<'_, WorldRenderSettings>, render_settings: ResMut<'_, WorldRenderSettings>,
) { ) {
// Add Julia-Mono font to egui // Add Julia-Mono font to egui
{ {
let egui_context = egui_context.into_inner(); let egui_context = egui_context.into_inner();
let ctx = egui_context.ctx_mut(); let ctx = egui_context.ctx_mut();
@ -126,19 +128,15 @@ fn generate_graphics(
ctx.set_fonts(fonts); ctx.set_fonts(fonts);
let mut style = (*ctx.style()).clone(); let mut style = (*ctx.style()).clone();
// Make all text 33% bigger because I have bad eyes (and the font is small)
for style in style.text_styles.iter_mut() { for style in style.text_styles.iter_mut() {
style.1.size *= 16.0 / 12.0; style.1.size *= 16.0 / 12.0;
} }
ctx.set_style(style); ctx.set_style(style);
#[cfg(feature = "logging")] // #[cfg(feature = "logging")]
debug!("Fonts: {:#?}", &ctx.style().text_styles); // debug!("Fonts: {:#?}", &ctx.style().text_styles);
} }
let world = world_manager.world();
let custom_sprite_size = Vec2 {
x: (WORLD_SCALE * world.width as i32) as f32,
y: (WORLD_SCALE * world.height as i32) as f32,
};
// Set up 2D map mode // Set up 2D map mode
{ {
use bevy::render::render_resource::{ use bevy::render::render_resource::{
@ -150,7 +148,7 @@ fn generate_graphics(
let images = images.into_inner(); let images = images.into_inner();
let mut render_settings = render_settings.into_inner(); let mut render_settings = render_settings.into_inner();
let map_image_handle = images.add(Image { let map_image_handle = images.add(Image {
data: vec![], data: vec![0; 16],
texture_descriptor: TextureDescriptor { texture_descriptor: TextureDescriptor {
label: None, label: None,
size: default(), size: default(),
@ -167,12 +165,7 @@ fn generate_graphics(
// TODO: Switch to egui // TODO: Switch to egui
_ = commands.spawn(SpriteBundle { _ = commands.spawn(SpriteBundle {
texture: images texture: images.get_handle(render_settings.map_image_handle_id.unwrap()),
.get_handle(unsafe { render_settings.map_image_handle_id.unwrap_unchecked() }),
sprite: Sprite {
custom_size: Some(custom_sprite_size),
..default()
},
..default() ..default()
}); });
} }
@ -224,7 +217,17 @@ fn redraw_map(
world_manager: Res<WorldManager>, world_manager: Res<WorldManager>,
render_settings: Res<'_, WorldRenderSettings>, render_settings: Res<'_, WorldRenderSettings>,
mut images: ResMut<Assets<Image>>, mut images: ResMut<Assets<Image>>,
mut map_sprite: Query<'_, '_, &mut Sprite>,
) { ) {
let Some(world) = world_manager.get_world() else {
#[cfg(feature = "logging")]
if should_redraw.0 {
debug!("Couldn't redraw map despite wanting to, because world isn't generated");
}
return;
};
assert!(world.width > 0);
if should_redraw.0 { if should_redraw.0 {
let world_manager: &WorldManager = &world_manager; let world_manager: &WorldManager = &world_manager;
let render_settings: &WorldRenderSettings = &render_settings; let render_settings: &WorldRenderSettings = &render_settings;
@ -239,60 +242,61 @@ fn redraw_map(
let map_image = images let map_image = images
.get_mut(&map_image_handle) .get_mut(&map_image_handle)
.expect("Map image handle pointing to non-existing image"); .expect("Map image handle pointing to non-existing image");
#[cfg(feature = "logging")]
debug!("Resizing image to {}x{}", world.width, world.height);
map_image.resize(bevy::render::render_resource::Extent3d { map_image.resize(bevy::render::render_resource::Extent3d {
width: world_manager.world().width, width: world.width,
height: world_manager.world().height, height: world.height,
depth_or_array_layers: 1, ..default()
}); });
map_image.data = world_manager.map_color_bytes(render_settings); map_image.data = world_manager.map_color_bytes(render_settings);
map_sprite.single_mut().custom_size = Some(Vec2 {
x: (world.width * WORLD_SCALE as u32) as f32,
y: (world.height * WORLD_SCALE as u32) as f32,
});
should_redraw.0 = false; should_redraw.0 = false;
} }
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
const WORLD_SCALE: i32 = 2; const WORLD_SCALE: i32 = 4;
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut app = App::new(); let mut app = App::new();
let mut manager = WorldManager::new();
#[cfg(feature = "render")] #[cfg(feature = "render")]
{ {
use bevy::winit::WinitSettings; use bevy::winit::{UpdateMode, WinitSettings};
let world = manager.new_world(Some(0))?;
_ = app _ = app
.insert_resource(WinitSettings::game()) .insert_resource(WinitSettings {
focused_mode: UpdateMode::Continuous,
unfocused_mode: UpdateMode::ReactiveLowPower {
max_wait: std::time::Duration::from_secs(10),
},
..default()
})
.insert_resource(CursorMapPosition::default()) .insert_resource(CursorMapPosition::default())
.insert_resource(OpenedWindows::default()) .insert_resource(OpenedWindows::default())
.insert_resource(WorldRenderSettings::default()) .insert_resource(WorldRenderSettings::default())
.insert_resource(ShouldRedraw::default()) .insert_resource(ShouldRedraw::default())
.insert_resource(GenerateWorldTask::default())
.add_startup_system(generate_graphics) .add_startup_system(generate_graphics)
.add_system(update_gui) .add_system(update_gui)
.add_system(update_cursor_map_position) .add_system(update_cursor_map_position)
.add_system(open_tile_info) .add_system(open_tile_info)
.add_system(redraw_map); .add_system(redraw_map);
app.add_plugins(WorldPlugins.set(WindowPlugin { app.add_plugins(WorldPlugins);
window: WindowDescriptor {
width: (WORLD_SCALE * world.width as i32) as f32,
height: (WORLD_SCALE * world.height as i32) as f32,
title: String::from("World-RS"),
resizable: true,
..default()
},
..default()
}));
} }
#[cfg(not(feature = "render"))] #[cfg(not(feature = "render"))]
{ {
_ = manager.new_world(Some(0))?;
app.add_plugins(WorldPlugins); app.add_plugins(WorldPlugins);
} }
app.add_system(handle_generate_world_task) app.insert_resource(WorldManager::new())
.insert_resource(manager) .insert_resource(GenerateWorldTask(
/* Some(manager.new_world_async(Some(0))) */ None,
))
.add_system(handle_generate_world_task)
.run(); .run();
Ok(()) Ok(())

View file

@ -173,7 +173,10 @@ pub(crate) trait WorldRenderer {
impl WorldRenderer for WorldManager { impl WorldRenderer for WorldManager {
#[must_use] #[must_use]
fn map_color_bytes(&self, render_settings: &WorldRenderSettings) -> Vec<u8> { fn map_color_bytes(&self, render_settings: &WorldRenderSettings) -> Vec<u8> {
self.world() let Some(world) = self.get_world() else {
return vec![];
};
world
.terrain .terrain
.iter() .iter()
.rev() .rev()
@ -190,10 +193,11 @@ impl WorldRenderer for WorldManager {
#[must_use] #[must_use]
fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color { fn generate_color(&self, cell: &TerrainCell, render_settings: &WorldRenderSettings) -> Color {
let world = self.get_world().expect("No world in generate_color");
let base_color = match render_settings.view { let base_color = match render_settings.view {
WorldView::Biomes => biome_color(self.world(), cell), WorldView::Biomes => biome_color(world, cell),
WorldView::Topography => altitude_contour_color(self.world(), cell.altitude), WorldView::Topography => altitude_contour_color(world, cell.altitude),
WorldView::Coastlines => coastline_color(self.world(), cell), WorldView::Coastlines => coastline_color(world, cell),
}; };
let mut normalizer = 1.0; let mut normalizer = 1.0;

View file

@ -46,7 +46,16 @@ impl PluginGroup for WorldPlugins {
group_builder = group_builder group_builder = group_builder
.add(TransformPlugin) .add(TransformPlugin)
.add(InputPlugin) .add(InputPlugin)
.add(WindowPlugin::default()) .add(WindowPlugin {
window: WindowDescriptor {
width: 1600.0,
height: 800.0,
title: String::from("World-RS"),
resizable: true,
..default()
},
..default()
})
.add(AssetPlugin::default()) .add(AssetPlugin::default())
.add(RenderPlugin) .add(RenderPlugin)
.add(ImagePlugin::default_nearest()) .add(ImagePlugin::default_nearest())

View file

@ -19,15 +19,8 @@ impl Display for CursorMapPosition {
} }
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[derive(Resource)] #[derive(Resource, Default)]
pub(crate) struct ShouldRedraw(pub(crate) bool); pub(crate) struct ShouldRedraw(pub(crate) bool);
#[cfg(feature = "render")]
impl Default for ShouldRedraw {
fn default() -> Self {
Self(true)
}
}
#[cfg(feature = "render")] #[cfg(feature = "render")]
#[derive(Default, Resource)] #[derive(Default, Resource)]
pub(crate) struct OpenedWindows(HashSet<WindowId>); pub(crate) struct OpenedWindows(HashSet<WindowId>);