diff --git a/Cargo.lock b/Cargo.lock index 76a9aff..b7ee597 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -888,9 +888,9 @@ checksum = "8050e2869fe341db6874203b5a01ff12673807a2c7c80cb829f6c7bea6997268" [[package]] name = "bevy_rapier3d" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac2b344d110e8aff2dab7ca6ed428dfcbbfeeb8f20827825996538f24e7fcdf" +checksum = "56691c8fbd7a8614368011bad8736789bb36176f49fc19fd6f3627322134659b" dependencies = [ "bevy", "bitflags 2.5.0", @@ -1326,6 +1326,8 @@ name = "buildings" version = "0.1.0" dependencies = [ "bevy", + "bevy_rapier3d", + "shared", "world_generation", ] @@ -3160,6 +3162,15 @@ dependencies = [ "libredox", ] +[[package]] +name = "ordered-float" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" +dependencies = [ + "num-traits", +] + [[package]] name = "overload" version = "0.1.1" @@ -3206,15 +3217,16 @@ dependencies = [ [[package]] name = "parry3d" -version = "0.13.7" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ccba18a65dba56c08dadfa936e0c9efbc883b3a26dc77d2685f78be10f7667c" +checksum = "aa342e0cdfc774fed0196714290ba2d85408b8ce9f295c40a0b1e05f3f8256ab" dependencies = [ "approx", "arrayvec", "bitflags 1.3.2", "downcast-rs", "either", + "log", "nalgebra", "num-derive", "num-traits", @@ -3258,6 +3270,7 @@ dependencies = [ "iyes_perf_ui", "noise 0.8.2", "rayon", + "shared", "world_generation", ] @@ -3483,9 +3496,9 @@ checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" [[package]] name = "rapier3d" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d07a833e0aa3bc57010caaa50bf75fa78afc03a74207607db740da4e4579a1" +checksum = "93ce0398df94b282787ddd36a3a9c7e1ca19fa1e79722a2debc49c9f7c06e889" dependencies = [ "approx", "arrayvec", @@ -3493,9 +3506,11 @@ dependencies = [ "bitflags 1.3.2", "crossbeam", "downcast-rs", + "log", "nalgebra", "num-derive", "num-traits", + "ordered-float", "parry3d", "rayon", "rustc-hash", @@ -3768,6 +3783,13 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared" +version = "0.1.0" +dependencies = [ + "bevy", +] + [[package]] name = "shlex" version = "1.3.0" diff --git a/Cargo.toml b/Cargo.toml index 585fbbf..a5b56d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,9 @@ resolver = "2" members = [ "game/main", "game/buildings", + "game/shared", "engine/world_generation", - "engine/asset_loader", "game/buildings"] + "engine/asset_loader", "game/buildings", "game/shared"] # Enable a small amount of optimization in debug mode [profile.dev] diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index b044427..e6de7b8 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -5,5 +5,6 @@ pub mod heightmap; pub mod hex_utils; pub mod map; pub mod prelude; +pub mod states; pub mod tile_manager; pub mod tile_mapper; diff --git a/engine/world_generation/src/map/map.rs b/engine/world_generation/src/map/map.rs index ce7874e..dbaccf3 100644 --- a/engine/world_generation/src/map/map.rs +++ b/engine/world_generation/src/map/map.rs @@ -107,7 +107,7 @@ impl Map { pub fn hex_select(&self, center: &HexCoord, radius: usize, include_center: bool, op: OP) -> Vec where - OP: Fn(&HexCoord, f32, usize) -> Ret + Sync + Send, + OP: (Fn(&HexCoord, f32, usize) -> Ret) + Sync + Send, { assert!(radius != 0, "Radius cannot be zero"); @@ -140,7 +140,7 @@ impl Map { op: OP, ) -> Vec where - OP: Fn(&HexCoord, &mut f32, usize) -> Ret + Sync + Send, + OP: (Fn(&HexCoord, &mut f32, usize) -> Ret) + Sync + Send, { assert!(radius != 0, "Radius cannot be zero"); diff --git a/engine/world_generation/src/prelude.rs b/engine/world_generation/src/prelude.rs index 1c85b04..3dbc12b 100644 --- a/engine/world_generation/src/prelude.rs +++ b/engine/world_generation/src/prelude.rs @@ -3,3 +3,4 @@ pub use crate::map::chunk::*; pub use crate::map::config::*; pub use crate::map::map::*; pub use crate::map::mesh_chunk::*; +pub use crate::states::*; diff --git a/engine/world_generation/src/states.rs b/engine/world_generation/src/states.rs new file mode 100644 index 0000000..4376f9a --- /dev/null +++ b/engine/world_generation/src/states.rs @@ -0,0 +1,17 @@ +use bevy::ecs::schedule::States; + +#[derive(States, Debug, Clone, PartialEq, Eq, Hash)] +pub enum GeneratorState { + GenerateHeightmap, + SpawnMap, + Idle, + Regenerate, +} + +#[derive(States, Debug, Clone, PartialEq, Eq, Hash)] +pub enum AssetLoadState { + StartLoading, + Loading, + FinalizeAssets, + LoadComplete, +} diff --git a/game/buildings/Cargo.toml b/game/buildings/Cargo.toml index f6cadfd..1545251 100644 --- a/game/buildings/Cargo.toml +++ b/game/buildings/Cargo.toml @@ -8,6 +8,8 @@ edition = "2021" [dependencies] bevy = "0.13.2" world_generation = {path = "../../engine/world_generation"} +shared = {path = "../shared"} +bevy_rapier3d = "0.26.0" [features] tracing = [] diff --git a/game/buildings/src/building_plugin.rs b/game/buildings/src/building_plugin.rs new file mode 100644 index 0000000..605ebf6 --- /dev/null +++ b/game/buildings/src/building_plugin.rs @@ -0,0 +1,68 @@ +use bevy::{prelude::*, window::PrimaryWindow}; +use bevy_rapier3d::{pipeline::QueryFilter, plugin::RapierContext}; +use shared::{despawn::Despawn, states::GameplayState, tags::MainCamera}; +use world_generation::{hex_utils::HexCoord, map::map::Map}; + +pub struct BuildingPugin; + +impl Plugin for BuildingPugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, init); + app.add_systems(Update, hq_placement.run_if(in_state(GameplayState::PlaceHQ))); + } +} + +#[derive(Resource)] +struct IndicatorCube(Handle, Handle); + +fn init(mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>) { + let cube = Cuboid::from_size(Vec3::splat(1.)); + let mesh_handle = meshes.add(cube); + let mat_handle = materials.add(Color::WHITE); + commands.insert_resource(IndicatorCube(mesh_handle, mat_handle)); +} + +fn hq_placement( + cam_query: Query<(&GlobalTransform, &Camera), With>, + mut commands: Commands, + window: Query<&Window, With>, + mouse: Res>, + rapier_context: Res, + map: Res, + indicator: Res, +) { + let win = window.single(); + let (cam_transform, camera) = cam_query.single(); + let Some(cursor_pos) = win.cursor_position() else { + return; + }; + + let Some(cam_ray) = camera.viewport_to_world(cam_transform, cursor_pos) else { + return; + }; + + let collision = rapier_context.cast_ray( + cam_ray.origin, + cam_ray.direction.into(), + 500., + true, + QueryFilter::only_fixed(), + ); + + if let Some((_e, dist)) = collision { + let contact_point = cam_ray.get_point(dist); + let contact_coord = HexCoord::from_world_pos(contact_point); + let positions = map.hex_select(&contact_coord, 3, true, |pos, h, _| pos.to_world(h)); + for p in positions { + commands.spawn(( + PbrBundle { + mesh: indicator.0.clone(), + material: indicator.1.clone(), + transform: Transform::from_translation(p), + ..default() + }, + Despawn, + )); + } + } +} diff --git a/game/buildings/src/lib.rs b/game/buildings/src/lib.rs index 0e98d5c..c365e83 100644 --- a/game/buildings/src/lib.rs +++ b/game/buildings/src/lib.rs @@ -1 +1,4 @@ pub mod buildings_database; +pub mod building_plugin; + +pub use building_plugin::*; \ No newline at end of file diff --git a/game/main/Cargo.toml b/game/main/Cargo.toml index 2fe4c00..2991916 100644 --- a/game/main/Cargo.toml +++ b/game/main/Cargo.toml @@ -12,9 +12,10 @@ bevy-inspector-egui = "0.23.4" iyes_perf_ui = "0.2.3" noise = "0.8.2" world_generation ={path="../../engine/world_generation"} -bevy_rapier3d = { version = "0.25.0", features = [ "simd-stable","parallel" ] } +bevy_rapier3d = { version = "0.26.0", features = [ "simd-stable","parallel" ] } rayon = "1.10.0" buildings = {path="../buildings"} +shared = {path="../shared"} [features] tracing = ["bevy/trace_tracy", "world_generation/tracing", "buildings/tracing"] \ No newline at end of file diff --git a/game/main/src/camera_system/camera_plugin.rs b/game/main/src/camera_system/camera_plugin.rs index a40ea55..e44cf9f 100644 --- a/game/main/src/camera_system/camera_plugin.rs +++ b/game/main/src/camera_system/camera_plugin.rs @@ -2,6 +2,8 @@ use bevy::core_pipeline::experimental::taa::{TemporalAntiAliasBundle, TemporalAn use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel}; use bevy::prelude::*; use bevy::window::CursorGrabMode; +use shared::states::GameState; +use shared::tags::MainCamera; use world_generation::hex_utils::HexCoord; use world_generation::prelude::Map; @@ -15,7 +17,7 @@ impl Plugin for PhosCameraPlugin { app.add_systems(PreStartup, setup); - app.add_systems(Update, rts_camera_system); + app.add_systems(Update, rts_camera_system.run_if(in_state(GameState::Playing))); app.add_systems(PostUpdate, limit_camera_bounds); //Free Cam //app.add_systems(Update, (grab_mouse, (update_camera, update_camera_mouse).chain())); @@ -32,6 +34,7 @@ fn setup(mut commands: Commands, mut msaa: ResMut) { ..default() }, PhosCamera::default(), + MainCamera, PhosCameraTargets::default(), )) .insert(TemporalAntiAliasBundle::default()); diff --git a/game/main/src/map_rendering/map_init.rs b/game/main/src/map_rendering/map_init.rs index d359fa7..0ca6c6a 100644 --- a/game/main/src/map_rendering/map_init.rs +++ b/game/main/src/map_rendering/map_init.rs @@ -3,6 +3,7 @@ use bevy::log::*; use bevy::{asset::LoadState, pbr::ExtendedMaterial, prelude::*}; use bevy_inspector_egui::quick::ResourceInspectorPlugin; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use shared::states::{GameState, GameplayState}; use world_generation::{ biome_painter::*, heightmap::generate_heightmap, @@ -14,10 +15,10 @@ use world_generation::{ use crate::{ camera_system::components::*, - prelude::{ChunkAtlas, PhosChunk, PhosChunkRegistry, PhosMap}, + prelude::{ChunkAtlas, PhosChunk, PhosChunkRegistry}, shader_extensions::chunk_material::ChunkMaterial, utlis::{ - chunk_utils::{paint_map, prepare_chunk_mesh, prepare_chunk_mesh_with_collider}, + chunk_utils::{paint_map, prepare_chunk_mesh_with_collider}, render_distance_system::RenderDistanceVisibility, }, }; @@ -30,23 +31,46 @@ pub struct MapInitPlugin; impl Plugin for MapInitPlugin { fn build(&self, app: &mut App) { + app.insert_state(GeneratorState::GenerateHeightmap); + app.insert_state(AssetLoadState::StartLoading); + app.add_plugins(( - ResourceInspectorPlugin::::default(), ResourceInspectorPlugin::::default(), ChunkRebuildPlugin, TerraFormingTestPlugin, )); - app.add_systems(Startup, (load_textures, load_tiles)); - app.add_systems(PostStartup, create_map); + app.add_systems(Startup, (load_textures, load_tiles).in_set(AssetLoaderSet)); + app.add_systems(Startup, create_heightmap.in_set(GeneratorSet)); + + app.configure_sets(Startup, AssetLoaderSet.run_if(in_state(AssetLoadState::StartLoading))); + app.configure_sets( + Startup, + GeneratorSet.run_if(in_state(GeneratorState::GenerateHeightmap)), + ); + + app.add_systems(Update, check_asset_load.run_if(in_state(AssetLoadState::Loading))); + app.add_systems( + Update, + finalize_texture.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)) + .run_if(in_state(GeneratorState::SpawnMap)), + ); - app.add_systems(Update, finalize_texture); - app.add_systems(PostUpdate, (despawn_map, spawn_map).chain()); app.insert_resource(TileManager::default()); - app.insert_resource(PhosMap::default()); } } +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +struct GeneratorSet; +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +struct AssetLoaderSet; + fn load_textures( mut commands: Commands, asset_server: Res, @@ -67,26 +91,25 @@ fn load_textures( }); } -fn load_tiles(mut commands: Commands, asset_server: Res) { +fn load_tiles( + mut commands: Commands, + asset_server: Res, + mut next_state: ResMut>, +) { let handle: Handle = asset_server.load("biome_painters/terra.biomes.json"); commands.insert_resource(CurrentBiomePainter { handle }); + next_state.set(AssetLoadState::Loading); } -fn finalize_texture( +fn check_asset_load( asset_server: Res, - mut atlas: ResMut, - mut map: ResMut, - mut images: ResMut>, + atlas: Res, painter: Res, painter_load: Res, tile_load: Res, - mut chunk_materials: ResMut>>, mapper_load: Res, + mut next_state: ResMut>, ) { - if atlas.is_loaded { - return; - } - if !painter_load.is_all_loaded() || !tile_load.is_all_loaded() || !mapper_load.is_all_loaded() { return; } @@ -97,6 +120,16 @@ fn finalize_texture( if asset_server.load_state(painter.handle.clone()) != LoadState::Loaded { return; } + + next_state.set(AssetLoadState::FinalizeAssets); +} + +fn finalize_texture( + mut atlas: ResMut, + mut images: ResMut>, + mut chunk_materials: ResMut>>, + mut next_state: ResMut>, +) { let image = images.get_mut(&atlas.handle).unwrap(); let array_layers = 14; @@ -110,11 +143,15 @@ fn finalize_texture( }, }); atlas.chunk_material_handle = chunk_material; - map.ready = true; - map.regenerate = true; + + next_state.set(AssetLoadState::LoadComplete); } -fn create_map(mut commands: Commands, mut cam: Query<(&mut Transform, Entity), With>) { +fn create_heightmap( + mut commands: Commands, + mut cam: Query<(&mut Transform, Entity), With>, + mut next_state: ResMut>, +) { let config = GenerationConfig { layers: vec![ GeneratorLayer { @@ -193,6 +230,7 @@ fn create_map(mut commands: Commands, mut cam: Query<(&mut Transform, Entity), W commands.insert_resource(heightmap); commands.insert_resource(config); + next_state.set(GeneratorState::SpawnMap); } fn spawn_map( @@ -200,16 +238,15 @@ fn spawn_map( mut commands: Commands, mut meshes: ResMut>, atlas: Res, - mut map: ResMut, tile_assets: Res>, tile_mappers: Res>, biome_painters: Res>, painter: Res, + mut generator_state: ResMut>, + cur_game_state: Res>, + mut game_state: ResMut>, + mut gameplay_state: ResMut>, ) { - if !map.ready || !map.regenerate { - return; - } - map.regenerate = false; let b_painter = biome_painters.get(painter.handle.clone()); let cur_painter = b_painter.unwrap(); paint_map(&mut heightmap, cur_painter, &tile_assets, &tile_mappers); @@ -224,7 +261,6 @@ fn spawn_map( .collect(); let mut registry = PhosChunkRegistry::new(chunk_meshes.len()); - { #[cfg(feature = "tracing")] let _spawn_span = info_span!("Spawn Chunks").entered(); @@ -262,21 +298,24 @@ fn spawn_map( },)); commands.insert_resource(registry); + generator_state.set(GeneratorState::Idle); + if cur_game_state.get() != &GameState::Playing { + game_state.set(GameState::Playing); + gameplay_state.set(GameplayState::PlaceHQ); + } } fn despawn_map( mut commands: Commands, mut heightmap: ResMut, cfg: Res, - map: Res, chunks: Query>, + mut next_state: ResMut>, ) { - if !map.regenerate { - return; - } for chunk in chunks.iter() { commands.entity(chunk).despawn(); } *heightmap = generate_heightmap(&cfg, 4); + next_state.set(GeneratorState::SpawnMap); } diff --git a/game/main/src/map_rendering/terraforming_test.rs b/game/main/src/map_rendering/terraforming_test.rs index 21103a4..1525c21 100644 --- a/game/main/src/map_rendering/terraforming_test.rs +++ b/game/main/src/map_rendering/terraforming_test.rs @@ -1,6 +1,6 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_rapier3d::{pipeline::QueryFilter, plugin::RapierContext}; -use world_generation::{hex_utils::HexCoord, prelude::Map}; +use world_generation::{hex_utils::HexCoord, prelude::Map, states::GeneratorState}; use crate::{ camera_system::components::PhosCamera, @@ -11,7 +11,7 @@ pub struct TerraFormingTestPlugin; impl Plugin for TerraFormingTestPlugin { fn build(&self, app: &mut App) { - app.add_systems(Update, deform); + app.add_systems(Update, deform.run_if(in_state(GeneratorState::Idle))); } } @@ -35,8 +35,6 @@ fn deform( return; } - #[cfg(feature = "tracing")] - let span = info_span!("Deform Mesh").entered(); let win = window.single(); let (cam_transform, camera) = cam_query.single(); let Some(cursor_pos) = win.cursor_position() else { @@ -50,12 +48,14 @@ fn deform( let collision = rapier_context.cast_ray( cam_ray.origin, cam_ray.direction.into(), - 100., + 500., true, QueryFilter::only_fixed(), ); if let Some((e, dist)) = collision { + #[cfg(feature = "tracing")] + let span = info_span!("Deform Mesh").entered(); let contact_point = cam_ray.get_point(dist); let contact_coord = HexCoord::from_world_pos(contact_point); let modified_chunks = heightmap.create_crater(&contact_coord, 5, 5. * multi); diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 1a31d92..c541841 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -12,7 +12,10 @@ use bevy::{ use bevy_rapier3d::dynamics::{Ccd, RigidBody, Velocity}; use bevy_rapier3d::geometry::Collider; use bevy_rapier3d::plugin::{NoUserData, RapierPhysicsPlugin}; +use buildings::BuildingPugin; use iyes_perf_ui::prelude::*; +use shared::despawn::DespawnPuglin; +use shared::states::{GameState, GameplayState}; use world_generation::biome_painter::BiomePainterPlugin; use world_generation::tile_manager::TileAssetPlugin; use world_generation::tile_mapper::TileMapperAssetPlugin; @@ -26,8 +29,13 @@ impl Plugin for PhosGamePlugin { MapInitPlugin, MaterialPlugin::>::default(), RenderDistancePlugin, + BuildingPugin, + DespawnPuglin, )); + app.insert_state(GameState::Startup); + app.insert_state(GameplayState::Waiting); + //Systems - Startup app.add_systems(Startup, init_game); diff --git a/game/main/src/prelude.rs b/game/main/src/prelude.rs index d26e6f4..b3e9f44 100644 --- a/game/main/src/prelude.rs +++ b/game/main/src/prelude.rs @@ -14,13 +14,6 @@ pub struct ChunkAtlas { pub is_loaded: bool, } -#[derive(Resource, Default, Reflect)] -#[reflect(Resource)] -pub struct PhosMap { - pub ready: bool, - pub regenerate: bool, -} - #[derive(Component)] pub struct PhosChunk { pub index: usize, diff --git a/game/shared/Cargo.toml b/game/shared/Cargo.toml new file mode 100644 index 0000000..1f89fe4 --- /dev/null +++ b/game/shared/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "shared" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bevy = "0.13.2" + + +[features] +tracing = [] diff --git a/game/shared/src/despawn.rs b/game/shared/src/despawn.rs new file mode 100644 index 0000000..e9231ba --- /dev/null +++ b/game/shared/src/despawn.rs @@ -0,0 +1,47 @@ +use crate::states::GameState; +use bevy::prelude::*; + +pub struct DespawnPuglin; + +#[derive(Component)] +pub struct DespawnAt(f32); + +#[derive(Component)] +pub struct DespawnAfter(Timer); + +#[derive(Component)] +pub struct Despawn; + +impl Plugin for DespawnPuglin { + fn build(&self, app: &mut App) { + app.add_systems(PostUpdate, despawn_at); + app.add_systems( + PreUpdate, + (despawn, despawn_after).run_if(not(in_state(GameState::Paused))), + ); + } +} + +fn despawn_at(mut commands: Commands, time: Res