diff --git a/crates/common/src/functions.rs b/crates/common/src/functions.rs index e5a1d31..0e8354c 100644 --- a/crates/common/src/functions.rs +++ b/crates/common/src/functions.rs @@ -1,19 +1,19 @@ use bevy::prelude::*; -use crate::{constants::TILE_SIZE, types::BlockCoordinates}; +use crate::{constants::TILE_SIZE, types::IWorldCoordinates}; -pub fn world_position_to_world_coordinates(world_position: Vec3) -> BlockCoordinates { +pub fn world_position_to_world_coordinates(world_position: Vec3) -> IWorldCoordinates { let x = world_position.x / TILE_SIZE.x; let y = world_position.y / TILE_SIZE.y; let z = world_position.z; - BlockCoordinates(IVec3::new( + IWorldCoordinates(IVec3::new( x.round() as i32, y.round() as i32, z.round() as i32, )) } -pub fn world_coordinates_to_world_position(world_coordinates: BlockCoordinates) -> Vec3 { +pub fn world_coordinates_to_world_position(world_coordinates: IWorldCoordinates) -> Vec3 { let x = world_coordinates.0.x as f32 * TILE_SIZE.x; let y = world_coordinates.0.y as f32 * TILE_SIZE.y; let z = world_coordinates.0.z as f32; diff --git a/crates/common/src/types.rs b/crates/common/src/types.rs index 8e2d84a..9b6f6e2 100644 --- a/crates/common/src/types.rs +++ b/crates/common/src/types.rs @@ -6,27 +6,28 @@ use bevy::{ use crate::traits::Neighbors; +/// These are essentially rounded world coordinates. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Reflect)] -pub struct BlockCoordinates(pub IVec3); +pub struct IWorldCoordinates(pub IVec3); -impl BlockCoordinates { +impl IWorldCoordinates { /// Manually overrides the z value of the coordinates. - pub fn with_z_offset(mut self, z_offset: i32) -> BlockCoordinates { + pub fn with_z_offset(mut self, z_offset: i32) -> IWorldCoordinates { self.0.z = z_offset; self } } -impl Neighbors for BlockCoordinates { - fn same_layer_neighbors(&self) -> Vec<(BlockCoordinates, u32)> { +impl Neighbors for IWorldCoordinates { + fn same_layer_neighbors(&self) -> Vec<(IWorldCoordinates, u32)> { self.0 .same_layer_neighbors() .iter() - .map(|(vec, cost)| (BlockCoordinates(*vec), *cost)) + .map(|(vec, cost)| (IWorldCoordinates(*vec), *cost)) .collect() } - fn all_neighbors(&self) -> Vec<(BlockCoordinates, u32)> { + fn all_neighbors(&self) -> Vec<(IWorldCoordinates, u32)> { todo!("not implemented") } } @@ -43,17 +44,18 @@ impl From<(u32, u32, u32)> for ChunkBlockCoordinates { } } +/// World coordinates that can be directly taken from a translation. #[derive(Clone, Copy, Debug, PartialEq, Default, Reflect, Component)] pub struct WorldCoordinates(pub Vec3); impl WorldCoordinates { - pub fn block(&self) -> BlockCoordinates { - BlockCoordinates(self.0.round().as_ivec3()) + pub fn block(&self) -> IWorldCoordinates { + IWorldCoordinates(self.0.round().as_ivec3()) } } -impl From<&BlockCoordinates> for WorldCoordinates { - fn from(wc: &BlockCoordinates) -> WorldCoordinates { +impl From<&IWorldCoordinates> for WorldCoordinates { + fn from(wc: &IWorldCoordinates) -> WorldCoordinates { WorldCoordinates(wc.0.as_vec3()) } } diff --git a/crates/designations/src/designations.rs b/crates/designations/src/designations.rs index d7210ef..dab630c 100644 --- a/crates/designations/src/designations.rs +++ b/crates/designations/src/designations.rs @@ -2,14 +2,14 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_inspector_egui::bevy_egui::{EguiContexts, EguiPrimaryContextPass}; use camera::CameraLayer; use common::{ - functions::world_position_to_world_coordinates, states::AppState, types::BlockCoordinates, + functions::world_position_to_world_coordinates, states::AppState, types::IWorldCoordinates, }; use leafwing_input_manager::{ Actionlike, plugin::InputManagerPlugin, prelude::{ActionState, InputMap, MouseMove}, }; -use map_generation::map_generation::WorldMap; +use map_generation::world_map::WorldMap; use work::{WorkOrder, work_order_queue::WorkOrderQueue}; use crate::ui; @@ -23,7 +23,7 @@ pub(crate) enum MouseActions { #[derive(Message)] enum BrushInputEvent { - Designated(BlockCoordinates), + Designated(IWorldCoordinates), } #[derive(Default, Reflect, Resource)] diff --git a/crates/map_generation/readme.md b/crates/map_generation/readme.md index e583383..56e2d81 100644 --- a/crates/map_generation/readme.md +++ b/crates/map_generation/readme.md @@ -2,6 +2,11 @@ This crate is responsible for generating and maintaining the maps. +## Interaction +When possible, the world map shouldn't be changed from outside the crate. Use +`UpdateMap` to send messages to the map, like `UpdateMap::Damage(...)`. +The map in turn will then send `MapUpdate` events to let others know of updates. + ## Visualisation and rendering * Every chunk should be rendered as a single Sprite/Mesh * Starting at the current layer every tile is checked downards (negative z direction). If a solid tile is hit, that tile will be rendered diff --git a/crates/map_generation/src/chunk.rs b/crates/map_generation/src/chunk.rs index e0e61b5..ff90b55 100644 --- a/crates/map_generation/src/chunk.rs +++ b/crates/map_generation/src/chunk.rs @@ -1,5 +1,5 @@ use bevy::prelude::*; -use common::types::{BlockCoordinates, ChunkBlockCoordinates, ChunkCoordinates}; +use common::types::{ChunkBlockCoordinates, ChunkCoordinates, IWorldCoordinates}; use noise::{NoiseFn, OpenSimplex}; use crate::block_type::{BlockType, SolidMaterial}; @@ -55,7 +55,7 @@ pub(crate) trait ToChunkAndBlock { fn to_chunk_and_block(&self) -> (ChunkCoordinates, ChunkBlockCoordinates); } -impl ToChunkAndBlock for BlockCoordinates { +impl ToChunkAndBlock for IWorldCoordinates { fn to_chunk_and_block(&self) -> (ChunkCoordinates, ChunkBlockCoordinates) { ( ChunkCoordinates(self.0.div_euclid(CHUNK_SIZE.as_ivec3())), @@ -75,12 +75,12 @@ pub(crate) fn to_index(coordinates: impl Into) -> usize { pub(crate) fn to_world_coordinates( chunk_coordinates: ChunkCoordinates, block_coordinates: impl Into, -) -> BlockCoordinates { +) -> IWorldCoordinates { let block_coordinates: ChunkBlockCoordinates = block_coordinates.into(); let x = chunk_coordinates.0.x * CHUNK_SIZE.x as i32 + block_coordinates.0.x as i32; let y = chunk_coordinates.0.y * CHUNK_SIZE.y as i32 + block_coordinates.0.y as i32; let z = chunk_coordinates.0.z * CHUNK_SIZE.z as i32 + block_coordinates.0.z as i32; - BlockCoordinates(IVec3::new(x, y, z)) + IWorldCoordinates(IVec3::new(x, y, z)) } #[test] @@ -101,6 +101,6 @@ fn test_to_world() { let chunk_coordinates = ChunkCoordinates(IVec3::ZERO); assert_eq!( to_world_coordinates(chunk_coordinates, (1, 2, 3)), - BlockCoordinates(IVec3::new(1, 2, 3)) + IWorldCoordinates(IVec3::new(1, 2, 3)) ) } diff --git a/crates/map_generation/src/chunk_visualisation.rs b/crates/map_generation/src/chunk_visualisation.rs index fa34a78..2c204dd 100644 --- a/crates/map_generation/src/chunk_visualisation.rs +++ b/crates/map_generation/src/chunk_visualisation.rs @@ -7,18 +7,15 @@ use bevy_ecs_tilemap::{ tiles::{AnimatedTile, TileBundle, TileColor, TilePos, TileStorage, TileTextureIndex}, }; use camera::CameraLayer; -use common::{ - constants::TILE_SIZE, - traits::Neighbors, - types::{BlockCoordinates, ChunkCoordinates}, -}; +use common::{constants::TILE_SIZE, traits::Neighbors, types::ChunkCoordinates}; use std::ops::{Range, RangeInclusive}; use crate::{ ToChunkAndBlock, block_type::BlockType, chunk::{CHUNK_SIZE, to_world_coordinates}, - map_generation::WorldMap, + messages::BlockUpdate, + world_map::WorldMap, }; /// actually spawns chunk visualisations @@ -245,45 +242,46 @@ fn spawn_tile_map( .insert(ChildOf(target)); } -pub(crate) fn on_chunk_visualisation_event( - trigger: On, +pub(crate) fn update( query: Query<(Entity, &ChunkVisualisation)>, + mut message_reader: MessageReader, mut commands: Commands, ) { - let ChunkVisualisationEvent::SetDirty(coordinates) = trigger.event(); - let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); + for block_update in message_reader.read() { + match block_update { + BlockUpdate::Added => todo!(), + BlockUpdate::Removed(world_coordinates) => { + let (chunk_coordinates, block_coordinates) = world_coordinates.to_chunk_and_block(); - let mut all = vec![chunk_coordinates]; - if block_coordinates.0.x == 0 - || block_coordinates.0.y == 0 - || block_coordinates.0.x == CHUNK_SIZE.x - 1 - || block_coordinates.0.y == CHUNK_SIZE.y - 1 - { - let neighbors: Vec = chunk_coordinates - .0 - .same_layer_neighbors() - .iter() - .map(|(coordinate, _)| ChunkCoordinates(*coordinate)) - .collect(); - all.extend(neighbors); - } - for coordinates in all { - if let Some((entity, _)) = query - .iter() - .find(|(_, chunk_vis)| chunk_vis.0 == coordinates) - { - commands - .entity(entity) - .insert(ChunkVisualisation(coordinates)); + let mut all = vec![chunk_coordinates]; + if block_coordinates.0.x == 0 + || block_coordinates.0.y == 0 + || block_coordinates.0.x == CHUNK_SIZE.x - 1 + || block_coordinates.0.y == CHUNK_SIZE.y - 1 + { + let neighbors: Vec = chunk_coordinates + .0 + .same_layer_neighbors() + .iter() + .map(|(coordinate, _)| ChunkCoordinates(*coordinate)) + .collect(); + all.extend(neighbors); + } + for coordinates in all { + if let Some((entity, _)) = query + .iter() + .find(|(_, chunk_vis)| chunk_vis.0 == coordinates) + { + commands + .entity(entity) + .insert(ChunkVisualisation(coordinates)); + } + } + } } } } -#[derive(Event)] -pub enum ChunkVisualisationEvent { - SetDirty(BlockCoordinates), -} - #[derive(Component, Reflect)] #[reflect(Component)] pub(crate) struct ChunkVisualisation(ChunkCoordinates); diff --git a/crates/map_generation/src/lib.rs b/crates/map_generation/src/lib.rs index f684510..3890495 100644 --- a/crates/map_generation/src/lib.rs +++ b/crates/map_generation/src/lib.rs @@ -1,9 +1,11 @@ -use chunk::{Chunk, ToChunkAndBlock, to_index}; +use chunk::ToChunkAndBlock; use chunk_visualisation::ChunkVisualisation; pub mod block_type; mod chunk; pub mod chunk_visualisation; pub mod map_generation; +pub mod messages; +pub mod world_map; pub use map_generation::plugin; diff --git a/crates/map_generation/src/map_generation.rs b/crates/map_generation/src/map_generation.rs index 9390e05..d0d1afd 100644 --- a/crates/map_generation/src/map_generation.rs +++ b/crates/map_generation/src/map_generation.rs @@ -1,12 +1,6 @@ -use bevy::{platform::collections::HashMap, prelude::*}; +use bevy::prelude::*; use bevy_ecs_tilemap::TilemapPlugin; -use common::{ - constants::TILE_SIZE, - states::AppState, - traits::{AddNamedObserver, Neighbors}, - types::{BlockCoordinates, ChunkCoordinates}, -}; -use noise::OpenSimplex; +use common::{constants::TILE_SIZE, states::AppState, traits::AddNamedObserver}; #[derive(Default, Reflect, Resource)] #[reflect(Resource)] @@ -15,109 +9,31 @@ pub struct WorldGenerationSettings { } use crate::{ - Chunk, ChunkVisualisation, ToChunkAndBlock, block_type::BlockType, chunk_visualisation, - to_index, + ChunkVisualisation, chunk_visualisation, + messages::{BlockUpdate, UpdateMap}, + world_map::WorldMap, }; pub fn plugin(app: &mut App) { app.register_type::() .register_type::() .register_type::() + .add_message::() + .add_message::() .insert_resource(ClearColor(Color::srgb_u8(50, 45, 52))) .add_plugins(TilemapPlugin) .add_systems(OnEnter(AppState::MainGame), spawn_world) .add_systems( Update, - (chunk_visualisation::request, chunk_visualisation::delete) + ( + handle_messages, + chunk_visualisation::update, + chunk_visualisation::request, + chunk_visualisation::delete, + ) .run_if(in_state(AppState::MainGame)), ) - .add_named_observer(chunk_visualisation::on_insert, "on_chunk_vis_insert") - .add_named_observer( - chunk_visualisation::on_chunk_visualisation_event, - "on_chunk_vis_event", - ); -} - -#[derive(Resource, Reflect)] -#[reflect(Resource)] -pub struct WorldMap { - chunks: HashMap, - #[reflect(ignore)] - noise: OpenSimplex, - pub(crate) entity: Entity, - block_states: HashMap, -} - -impl WorldMap { - fn new(entity: Entity, seed: u32) -> Self { - WorldMap { - chunks: HashMap::default(), - noise: OpenSimplex::new(seed), - entity, - block_states: HashMap::default(), - } - } - - /// Checks every surrounding chunk. If it doesn't exist, it will be created. - pub(crate) fn ensure_surrounding_exist(&mut self, coordinates: ChunkCoordinates) { - self.get_or_insert_chunk_mut(coordinates); - for (neighbor, _) in coordinates.0.all_neighbors() { - self.get_or_insert_chunk_mut(ChunkCoordinates(neighbor)); - } - } - - /// Returns a chunk for a given coordinate. Will create a new one, if none has been created thus far. - fn get_or_insert_chunk_mut(&mut self, coordinates: ChunkCoordinates) -> &mut Chunk { - self.chunks - .entry(coordinates.0) - .or_insert(Chunk::new(coordinates, self.noise)) - } - - /// Tries to fetch a block from world. Will return None, if the chunk doesn't exist or the block is of type BlockType::None - pub fn get_block(&self, coordinates: BlockCoordinates) -> Option { - let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); - let index = to_index(block_coordinates); - self.chunks - .get(&chunk_coordinates.0) - .and_then(|chunk| match chunk.blocks[index] { - BlockType::None => None, - _ => Some(chunk.blocks[index]), - }) - } - - /// Returns a result of type BlockType, if the corresponding chunk has been found. Returns an empty error, when the chunk is not loaded. - pub fn get_raw_block(&self, coordinates: BlockCoordinates) -> Option { - let (chunk_coordinate, block_coordinates) = coordinates.to_chunk_and_block(); - let index = to_index(block_coordinates); - self.chunks - .get(&chunk_coordinate.0) - .map(|chunk| chunk.blocks[index]) - } - - pub fn solidness(&self, coordinates: BlockCoordinates) -> bool { - let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); - let index = to_index(block_coordinates); - self.chunks - .get(&chunk_coordinates.0) - .is_none_or(|chunk| chunk.blocks[index].is_solid()) - } - - /// Adds damage to a block. Returns true, if the block is destroyed, false otherwise. - pub fn damage_block(&mut self, coordinates: BlockCoordinates, damage: f32) -> bool { - let remaining_health = { - *self - .block_states - .entry(coordinates.0) - .and_modify(|block| *block -= damage) - .or_insert(1.0) - }; - if remaining_health < 0.0 { - let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); - self.get_or_insert_chunk_mut(chunk_coordinates) - .remove_block(block_coordinates); - } - remaining_health < 0.0 - } + .add_named_observer(chunk_visualisation::on_insert, "on_chunk_vis_insert"); } fn spawn_world(world_generation_settings: Res, mut commands: Commands) { @@ -132,3 +48,20 @@ fn spawn_world(world_generation_settings: Res, mut comm .id(); commands.insert_resource(WorldMap::new(entity, world_generation_settings.seed)); } + +fn handle_messages( + mut world_map: ResMut, + mut message_reader: MessageReader, + mut message_writer: MessageWriter, +) { + for update_message in message_reader.read() { + match update_message { + &UpdateMap::DamageBlock(world_coordinates, damage) => { + if world_map.damage_block(world_coordinates, damage) { + debug!("block {:?} was destroyed", world_coordinates); + message_writer.write(BlockUpdate::Removed(world_coordinates)); + } + } + } + } +} diff --git a/crates/map_generation/src/messages.rs b/crates/map_generation/src/messages.rs new file mode 100644 index 0000000..3afa630 --- /dev/null +++ b/crates/map_generation/src/messages.rs @@ -0,0 +1,16 @@ +use bevy::prelude::*; +use common::types::IWorldCoordinates; + +/// Messages to tell the map to update specific contents. +#[derive(Message)] +pub enum UpdateMap { + /// Tells the map to damage a block with the given coordinates and the + /// given damage + DamageBlock(IWorldCoordinates, f32), +} + +#[derive(Message)] +pub enum BlockUpdate { + Added, + Removed(IWorldCoordinates), +} diff --git a/crates/map_generation/src/world_map.rs b/crates/map_generation/src/world_map.rs new file mode 100644 index 0000000..625c003 --- /dev/null +++ b/crates/map_generation/src/world_map.rs @@ -0,0 +1,95 @@ +use std::collections::HashMap; + +use bevy::prelude::*; +use common::{ + traits::Neighbors, + types::{ChunkCoordinates, IWorldCoordinates}, +}; +use noise::OpenSimplex; + +use crate::{ + block_type::BlockType, + chunk::{Chunk, ToChunkAndBlock, to_index}, +}; + +#[derive(Resource, Reflect)] +#[reflect(Resource)] +pub struct WorldMap { + chunks: HashMap, + #[reflect(ignore)] + noise: OpenSimplex, + pub(crate) entity: Entity, + block_states: HashMap, +} + +impl WorldMap { + pub(crate) fn new(entity: Entity, seed: u32) -> Self { + WorldMap { + chunks: HashMap::default(), + noise: OpenSimplex::new(seed), + entity, + block_states: HashMap::default(), + } + } + + /// Checks every surrounding chunk. If it doesn't exist, it will be created. + pub(crate) fn ensure_surrounding_exist(&mut self, coordinates: ChunkCoordinates) { + self.get_or_insert_chunk_mut(coordinates); + for (neighbor, _) in coordinates.0.all_neighbors() { + self.get_or_insert_chunk_mut(ChunkCoordinates(neighbor)); + } + } + + /// Returns a chunk for a given coordinate. Will create a new one, if none has been created thus far. + fn get_or_insert_chunk_mut(&mut self, coordinates: ChunkCoordinates) -> &mut Chunk { + self.chunks + .entry(coordinates.0) + .or_insert(Chunk::new(coordinates, self.noise)) + } + + /// Tries to fetch a block from world. Will return None, if the chunk doesn't exist or the block is of type BlockType::None + pub fn get_block(&self, coordinates: IWorldCoordinates) -> Option { + let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); + let index = to_index(block_coordinates); + self.chunks + .get(&chunk_coordinates.0) + .and_then(|chunk| match chunk.blocks[index] { + BlockType::None => None, + _ => Some(chunk.blocks[index]), + }) + } + + /// Returns a result of type BlockType, if the corresponding chunk has been found. Returns an empty error, when the chunk is not loaded. + pub fn get_raw_block(&self, coordinates: IWorldCoordinates) -> Option { + let (chunk_coordinate, block_coordinates) = coordinates.to_chunk_and_block(); + let index = to_index(block_coordinates); + self.chunks + .get(&chunk_coordinate.0) + .map(|chunk| chunk.blocks[index]) + } + + pub fn solidness(&self, coordinates: IWorldCoordinates) -> bool { + let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); + let index = to_index(block_coordinates); + self.chunks + .get(&chunk_coordinates.0) + .is_none_or(|chunk| chunk.blocks[index].is_solid()) + } + + /// Adds damage to a block. Returns true, if the block is destroyed, false otherwise. + pub fn damage_block(&mut self, coordinates: IWorldCoordinates, damage: f32) -> bool { + let remaining_health = { + *self + .block_states + .entry(coordinates.0) + .and_modify(|block| *block -= damage) + .or_insert(1.0 - damage) + }; + if remaining_health <= 0.0 { + let (chunk_coordinates, block_coordinates) = coordinates.to_chunk_and_block(); + self.get_or_insert_chunk_mut(chunk_coordinates) + .remove_block(block_coordinates); + } + remaining_health < 0.0 + } +} diff --git a/crates/pathfinding/src/lib.rs b/crates/pathfinding/src/lib.rs index cd6df9c..2747b5f 100644 --- a/crates/pathfinding/src/lib.rs +++ b/crates/pathfinding/src/lib.rs @@ -1,6 +1,6 @@ use bevy::prelude::*; use common::traits::AddNamedObserver; -use map_generation::map_generation::WorldMap; +use map_generation::world_map::WorldMap; use path::Path; use pathfinder::{Pathfinder, PathfinderListener, PathfindingErrors, PathfindingState}; diff --git a/crates/pathfinding/src/path.rs b/crates/pathfinding/src/path.rs index 6a2df6b..16d3b5b 100644 --- a/crates/pathfinding/src/path.rs +++ b/crates/pathfinding/src/path.rs @@ -2,18 +2,18 @@ use bevy::prelude::*; use std::time::Duration; use crate::{PathEvent, PathState}; -use common::types::{BlockCoordinates, WorldCoordinates}; +use common::types::{IWorldCoordinates, WorldCoordinates}; #[derive(Clone, Component, Debug, PartialEq, Reflect)] #[reflect(Component)] pub struct Path { - set: Vec, + set: Vec, current_index: usize, current_t: f32, } impl Path { - pub(crate) fn new(set: Vec) -> Self { + pub(crate) fn new(set: Vec) -> Self { Path { set, current_index: 0, diff --git a/crates/pathfinding/src/pathfinder.rs b/crates/pathfinding/src/pathfinder.rs index 23e459c..bb5d228 100644 --- a/crates/pathfinding/src/pathfinder.rs +++ b/crates/pathfinding/src/pathfinder.rs @@ -1,8 +1,8 @@ use std::cmp::Reverse; use bevy::{ecs::spawn::SpawnIter, platform::collections::HashMap, prelude::*}; -use common::{traits::Neighbors, types::BlockCoordinates}; -use map_generation::{block_type::BlockType, map_generation::WorldMap}; +use common::{traits::Neighbors, types::IWorldCoordinates}; +use map_generation::{block_type::BlockType, world_map::WorldMap}; use priority_queue::PriorityQueue; use crate::path::Path; @@ -45,7 +45,7 @@ pub(crate) struct PathfinderListener; impl Pathfinder { /// Creates a new pathfinder that will try to find a path via A* from start to target - fn new(start: BlockCoordinates, target: BlockCoordinates) -> Self { + fn new(start: IWorldCoordinates, target: IWorldCoordinates) -> Self { let frontier = PriorityQueue::from(vec![(start.0, Reverse(0))]); let mut came_from = HashMap::default(); came_from.insert(start.0, None); @@ -63,7 +63,7 @@ impl Pathfinder { /// Spawns a PathfinderListener with one separate Pathfinder child target the exact block /// /// Use this, if an entity has to land exactly on the given target - pub fn exact(start: BlockCoordinates, target: BlockCoordinates) -> impl Bundle { + pub fn exact(start: IWorldCoordinates, target: IWorldCoordinates) -> impl Bundle { ( PathfinderListener, children![( @@ -76,7 +76,7 @@ impl Pathfinder { /// Spawns a PathfinderListener with separate Pathfinder children targeting the blocks surrounding the given target /// /// Use this if an entity has to come close to a given target but not go onto it - pub fn nearest(start: BlockCoordinates, target: BlockCoordinates) -> impl Bundle { + pub fn nearest(start: IWorldCoordinates, target: IWorldCoordinates) -> impl Bundle { let finders: Vec<(Pathfinder, Name)> = target .same_layer_neighbors() .iter() @@ -138,17 +138,19 @@ impl Pathfinder { world_map: &WorldMap, neighbor: IVec3, ) -> Result { - let neighbor_block = world_map.get_raw_block(BlockCoordinates(neighbor)).ok_or({ - if self.current_failures >= self.allowed_failures { - PathfindingErrors::Unreachable - } else { - PathfindingErrors::NotEnoughChunks - } - })?; + let neighbor_block = world_map + .get_raw_block(IWorldCoordinates(neighbor)) + .ok_or({ + if self.current_failures >= self.allowed_failures { + PathfindingErrors::Unreachable + } else { + PathfindingErrors::NotEnoughChunks + } + })?; trace!("checking {}, is {:?}", neighbor, neighbor_block); let block_below = world_map - .get_raw_block(BlockCoordinates(neighbor - IVec3::Z)) + .get_raw_block(IWorldCoordinates(neighbor - IVec3::Z)) .ok_or({ if self.current_failures >= self.allowed_failures { PathfindingErrors::Unreachable @@ -160,13 +162,13 @@ impl Pathfinder { Ok(neighbor_block == BlockType::None && matches!(block_below, BlockType::Solid(_))) } - fn to_path(&self) -> Vec { + fn to_path(&self) -> Vec { let mut points = vec![]; let mut next = self.target; - points.push(BlockCoordinates(next)); + points.push(IWorldCoordinates(next)); while let Some(point_option) = self.came_from.get(&next) { if let Some(point) = point_option { - points.push(BlockCoordinates(*point)); + points.push(IWorldCoordinates(*point)); next = *point; } else { break; diff --git a/crates/work/src/lib.rs b/crates/work/src/lib.rs index 080d985..334cc5f 100644 --- a/crates/work/src/lib.rs +++ b/crates/work/src/lib.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use common::{ traits::SpawnNamedObserver, - types::{BlockCoordinates, WorldCoordinates}, + types::{IWorldCoordinates, WorldCoordinates}, }; use tasks::{Task, TaskQueue, TaskState}; use work_order_queue::WorkOrderQueue; @@ -21,12 +21,12 @@ pub fn plugin(app: &mut App) { /// Represents work orders that can be created by the player #[derive(Clone, Component, Copy, Debug, PartialEq, Reflect)] pub enum WorkOrder { - Dig(BlockCoordinates), + Dig(IWorldCoordinates), } impl WorkOrder { /// Creates a digging work order for the given world position - pub fn dig(world_coordinates: BlockCoordinates) -> impl Bundle { + pub fn dig(world_coordinates: IWorldCoordinates) -> impl Bundle { ( Name::new(format!("WorkOrder - Dig {}", world_coordinates.0)), WorldCoordinates(world_coordinates.0.as_vec3()), diff --git a/crates/work/src/tasks.rs b/crates/work/src/tasks.rs index 043c70b..a59c1b6 100644 --- a/crates/work/src/tasks.rs +++ b/crates/work/src/tasks.rs @@ -1,7 +1,6 @@ use bevy::prelude::*; -use common::types::BlockCoordinates; +use common::types::IWorldCoordinates; use dig::Dig; -use map_generation::map_generation::WorldMap; use walk_to::WalkTo; use walk_to_nearest::WalkToNearest; @@ -19,7 +18,8 @@ pub(crate) fn plugin(app: &mut App) { Update, ( check_tasks, - dig::handle.run_if(resource_exists::), + dig::tick, + dig::cleanup, walk_to_nearest::handle, walk_to::handle, ), @@ -49,16 +49,16 @@ pub(crate) enum Task { } impl Task { - pub(crate) fn dig(pos: BlockCoordinates) -> Task { + pub(crate) fn dig(pos: IWorldCoordinates) -> Task { Task::Dig(Dig(pos)) } #[allow(dead_code)] - pub(crate) fn walk_to(pos: BlockCoordinates) -> Task { + pub(crate) fn walk_to(pos: IWorldCoordinates) -> Task { Task::WalkTo(WalkTo(pos)) } - pub(crate) fn walk_to_nearest(pos: BlockCoordinates) -> Task { + pub(crate) fn walk_to_nearest(pos: IWorldCoordinates) -> Task { Task::WalkToNearest(WalkToNearest(pos)) } } diff --git a/crates/work/src/tasks/dig.rs b/crates/work/src/tasks/dig.rs index f159aac..5fba283 100644 --- a/crates/work/src/tasks/dig.rs +++ b/crates/work/src/tasks/dig.rs @@ -1,23 +1,58 @@ use bevy::prelude::*; -use common::types::BlockCoordinates; -use map_generation::{chunk_visualisation::ChunkVisualisationEvent, map_generation::WorldMap}; +use common::types::IWorldCoordinates; +use map_generation::messages::{BlockUpdate, UpdateMap}; -use super::Task; +use crate::tasks::Task; #[derive(Clone, Component, Copy, Debug, Reflect)] #[reflect(Component)] -pub(crate) struct Dig(pub(crate) BlockCoordinates); +#[require(DigTimer)] +pub(crate) struct Dig(pub(crate) IWorldCoordinates); -pub(crate) fn handle( +#[derive(Component, Deref, DerefMut, Reflect)] +#[reflect(Component)] +pub(crate) struct DigTimer(Timer); + +impl Default for DigTimer { + fn default() -> Self { + DigTimer(Timer::from_seconds(0.25, TimerMode::Repeating)) + } +} + +pub(crate) fn tick( time: Res