Files
phos-neo/game/main/src/map_rendering/map_init.rs
2024-11-09 22:21:24 -05:00

305 lines
8.2 KiB
Rust

#[cfg(feature = "tracing")]
use bevy::log::*;
use bevy::{
pbr::{ExtendedMaterial, NotShadowCaster},
prelude::*,
render::render_resource::{ColorTargetState, FragmentState, RenderPipelineDescriptor},
};
use bevy_asset_loader::prelude::*;
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
use shared::states::{AssetLoadState, GameplayState, MenuState};
use world_generation::{
biome_asset::{BiomeAsset, BiomeAssetPlugin},
biome_painter::*,
heightmap::generate_heightmap,
hex_utils::{offset_to_index, SHORT_DIAGONAL},
map::biome_map::BiomeMap,
prelude::*,
tile_manager::*,
tile_mapper::*,
};
use crate::{
prelude::{PhosAssets, PhosChunk, PhosChunkRegistry},
shader_extensions::{
chunk_material::ChunkMaterial,
water_material::{WaterMaterial, WaterSettings},
},
utlis::chunk_utils::{paint_map, prepare_chunk_mesh_with_collider},
};
use super::{chunk_rebuild::ChunkRebuildPlugin, render_distance_system::RenderDistanceVisibility};
pub struct MapInitPlugin;
impl Plugin for MapInitPlugin {
fn build(&self, app: &mut App) {
app.insert_state(GeneratorState::Startup);
app.insert_state(AssetLoadState::Loading);
//Assets
app.add_plugins(TileAssetPlugin);
app.add_plugins(TileMapperAssetPlugin);
app.add_plugins(BiomeAssetPlugin);
app.add_plugins(ResourceInspectorPlugin::<GenerationConfig>::default());
app.register_type::<ExtendedMaterial<StandardMaterial, WaterMaterial>>();
app.register_asset_reflect::<ExtendedMaterial<StandardMaterial, WaterMaterial>>();
app.add_plugins((
ChunkRebuildPlugin,
// TerraFormingTestPlugin,
MaterialPlugin::<ChunkMaterial>::default(),
MaterialPlugin::<ExtendedMaterial<StandardMaterial, WaterMaterial>> {
prepass_enabled: false,
..Default::default()
},
));
app.configure_loading_state(
LoadingStateConfig::new(AssetLoadState::Loading)
.with_dynamic_assets_file::<StandardDynamicAssetCollection>("phos.assets.ron")
.load_collection::<PhosAssets>()
.load_collection::<BiomePainterAsset>(),
);
app.add_systems(
Update,
create_heightmap.run_if(in_state(GeneratorState::GenerateHeightmap)),
);
app.add_systems(
Update,
(finalize_texture, setup_materials, finalize_biome_painter)
.run_if(in_state(AssetLoadState::FinalizeAssets)),
);
app.add_systems(Update, despawn_map.run_if(in_state(GeneratorState::Regenerate)));
app.add_systems(
Update,
spawn_map.run_if(in_state(AssetLoadState::LoadComplete).and_then(in_state(GeneratorState::SpawnMap))),
);
app.insert_resource(TileManager::default());
}
}
fn setup_materials(
mut phos_assets: ResMut<PhosAssets>,
mut water_materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, WaterMaterial>>>,
) {
let water_material = water_materials.add(ExtendedMaterial {
base: StandardMaterial {
base_color: Color::srgb(0., 0.878, 1.),
alpha_mode: AlphaMode::Blend,
metallic: 1.0,
..Default::default()
},
extension: WaterMaterial {
settings: WaterSettings {
offset: -4.97,
scale: 1.,
deep_color: LinearRgba::rgb(0.0, 0.04, 0.085).into(),
..Default::default()
},
..default()
},
});
phos_assets.water_material = water_material;
}
fn finalize_biome_painter(
mut commands: Commands,
mut next_generator_state: ResMut<NextState<GeneratorState>>,
biome_painter: Res<BiomePainterAsset>,
biomes: Res<Assets<BiomeAsset>>,
) {
let painter = biome_painter.build(&biomes);
commands.insert_resource(painter);
next_generator_state.set(GeneratorState::GenerateHeightmap);
}
fn finalize_texture(
mut atlas: ResMut<PhosAssets>,
mut images: ResMut<Assets<Image>>,
mut chunk_materials: ResMut<Assets<ChunkMaterial>>,
mut next_load_state: ResMut<NextState<AssetLoadState>>,
) {
let image = images.get_mut(atlas.handle.id()).unwrap();
let array_layers = image.height() / image.width();
image.reinterpret_stacked_2d_as_array(array_layers);
let chunk_material = chunk_materials.add(ChunkMaterial {
array_texture: atlas.handle.clone(),
});
atlas.chunk_material_handle = chunk_material;
next_load_state.set(AssetLoadState::LoadComplete);
}
fn create_heightmap(
mut commands: Commands,
mut next_state: ResMut<NextState<GeneratorState>>,
biome_painter: Res<BiomePainter>,
) {
let config = GenerationConfig {
biome_blend: 32,
biome_dither: 10.,
continent_noise: NoiseConfig {
scale: 800.,
layers: vec![GeneratorLayer {
base_roughness: 2.14,
roughness: 0.87,
strength: 100.,
min_value: 0.,
persistence: 0.77,
is_rigid: false,
weight: 0.,
weight_multi: 0.,
layers: 1,
}],
},
moisture_noise: NoiseConfig {
scale: 900.,
layers: vec![GeneratorLayer {
base_roughness: 2.14,
roughness: 0.87,
strength: 100.,
min_value: 0.,
persistence: 0.77,
is_rigid: false,
weight: 0.,
weight_multi: 0.,
layers: 1,
}],
},
temperature_noise: NoiseConfig {
scale: 700.,
layers: vec![GeneratorLayer {
base_roughness: 2.14,
roughness: 0.87,
strength: 100.,
min_value: 0.,
persistence: 0.77,
is_rigid: false,
weight: 0.,
weight_multi: 0.,
layers: 1,
}],
},
sea_level: 8.5,
border_size: 64.,
size: UVec2::splat(16),
// size: UVec2::splat(1),
};
let (heightmap, biome_map) = generate_heightmap(&config, 42069, &biome_painter);
commands.insert_resource(heightmap);
commands.insert_resource(biome_map);
commands.insert_resource(config);
next_state.set(GeneratorState::SpawnMap);
}
fn spawn_map(
mut heightmap: ResMut<Map>,
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
atlas: Res<PhosAssets>,
tile_assets: Res<Assets<TileAsset>>,
tile_mappers: Res<Assets<TileMapperAsset>>,
mut generator_state: ResMut<NextState<GeneratorState>>,
cur_game_state: Res<State<MenuState>>,
mut game_state: ResMut<NextState<MenuState>>,
mut gameplay_state: ResMut<NextState<GameplayState>>,
biome_painter: Res<BiomePainter>,
) {
paint_map(&mut heightmap, &biome_painter, &tile_assets, &tile_mappers);
//Prepare Mesh Data
let map_size = UVec2::new(heightmap.width as u32, heightmap.height as u32);
let chunk_meshes: Vec<_> = heightmap
.chunks
.par_iter()
.map(|chunk: &Chunk| {
let index = offset_to_index(chunk.chunk_offset, heightmap.width);
return prepare_chunk_mesh_with_collider(
&heightmap.get_chunk_mesh_data(index),
heightmap.sealevel,
chunk.chunk_offset,
index,
map_size,
);
})
.collect();
let mut registry = PhosChunkRegistry::new(chunk_meshes.len());
//Spawn Chunks
{
#[cfg(feature = "tracing")]
let _spawn_span = info_span!("Spawn Chunks").entered();
let visibility_offset = Vec3::new(
(Chunk::SIZE / 2) as f32 * SHORT_DIAGONAL,
0.,
(Chunk::SIZE / 2) as f32 * 1.5,
);
for (chunk_mesh, water_mesh, collider, pos, index) in chunk_meshes {
// let mesh_handle = meshes.a
let chunk = commands
.spawn((
MaterialMeshBundle {
mesh: meshes.add(chunk_mesh),
material: atlas.chunk_material_handle.clone(),
transform: Transform::from_translation(pos),
..default()
},
PhosChunk::new(index),
RenderDistanceVisibility::default().with_offset(visibility_offset),
collider,
))
.id();
let water = commands
.spawn((
MaterialMeshBundle {
mesh: meshes.add(water_mesh),
material: atlas.water_material.clone(),
transform: Transform::from_translation(pos),
..default()
},
PhosChunk::new(index),
NotShadowCaster,
RenderDistanceVisibility::default().with_offset(visibility_offset),
))
.id();
registry.chunks.push(chunk);
registry.waters.push(water);
}
}
commands.insert_resource(registry);
generator_state.set(GeneratorState::Idle);
if cur_game_state.get() != &MenuState::InGame {
game_state.set(MenuState::InGame);
gameplay_state.set(GameplayState::PlaceHQ);
}
}
fn despawn_map(
mut commands: Commands,
mut heightmap: ResMut<Map>,
mut biome_map: ResMut<BiomeMap>,
cfg: Res<GenerationConfig>,
chunks: Query<Entity, With<PhosChunk>>,
mut next_state: ResMut<NextState<GeneratorState>>,
biome_painter: Res<BiomePainter>,
) {
for chunk in chunks.iter() {
commands.entity(chunk).despawn();
}
(*heightmap, *biome_map) = generate_heightmap(&cfg, 4, &biome_painter);
next_state.set(GeneratorState::SpawnMap);
}