diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index deb885dad6..4958350100 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -1,3 +1,4 @@ +use crate::terrain::{Block, BlockKind}; use specs::{Component, FlaggedStorage}; use specs_idvs::IDVStorage; @@ -70,6 +71,23 @@ impl Armor { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Consumable { + Apple, + Potion, + Mushroom, +} + +impl Consumable { + pub fn name(&self) -> &'static str { + match self { + Consumable::Apple => "apple", + Consumable::Potion => "potion", + Consumable::Mushroom => "mushroom", + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ConsumptionEffect { Health(i32), @@ -93,6 +111,7 @@ pub enum Item { health_bonus: i32, }, Consumable { + kind: Consumable, effect: ConsumptionEffect, }, Ingredient, @@ -123,6 +142,30 @@ impl Item { pub fn description(&self) -> String { format!("{} ({})", self.name(), self.category()) } + + pub fn try_reclaim_from_block(block: Block) -> Option { + match block.kind() { + BlockKind::Apple => Some(Self::apple()), + BlockKind::Mushroom => Some(Self::mushroom()), + _ => None, + } + } + + // General item constructors + + pub fn apple() -> Self { + Item::Consumable { + kind: Consumable::Apple, + effect: ConsumptionEffect::Health(3), + } + } + + pub fn mushroom() -> Self { + Item::Consumable { + kind: Consumable::Mushroom, + effect: ConsumptionEffect::Health(1), + } + } } impl Default for Item { diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index 618cd5b99a..11feae2b26 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -5,7 +5,6 @@ pub mod item; pub use self::item::{Debug, Item, Tool}; use specs::{Component, HashMapStorage, NullStorage}; -//use specs_idvs::IDVStorage; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Inventory { diff --git a/common/src/state.rs b/common/src/state.rs index 9c5b2035c1..fb800002a4 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -55,6 +55,15 @@ impl BlockChange { self.blocks.insert(pos, block); } + pub fn try_set(&mut self, pos: Vec3, block: Block) -> Option<()> { + if !self.blocks.contains_key(&pos) { + self.blocks.insert(pos, block); + Some(()) + } else { + None + } + } + pub fn clear(&mut self) { self.blocks.clear(); } @@ -234,11 +243,16 @@ impl State { self.ecs.write_resource() } - /// Get a writable reference to this state's terrain. + /// Set a block in this state's terrain. pub fn set_block(&mut self, pos: Vec3, block: Block) { self.ecs.write_resource::().set(pos, block); } + /// Set a block in this state's terrain. Will return `None` if the block has already been modified this tick. + pub fn try_set_block(&mut self, pos: Vec3, block: Block) -> Option<()> { + self.ecs.write_resource::().try_set(pos, block) + } + /// Removes every chunk of the terrain. pub fn clear_terrain(&mut self) { let keys = self diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index bd656fd5e6..f2b19361ee 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -32,6 +32,13 @@ pub enum BlockKind { } impl BlockKind { + pub fn is_tangeable(&self) -> bool { + match self { + BlockKind::Air => false, + kind => !kind.is_fluid(), + } + } + pub fn is_air(&self) -> bool { match self { BlockKind::Air => true, diff --git a/server/src/lib.rs b/server/src/lib.rs index 8d140a980d..c67fe80ea8 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -765,7 +765,6 @@ impl Server { let mut new_chat_msgs = Vec::new(); let mut disconnected_clients = Vec::new(); let mut requested_chunks = Vec::new(); - let mut modified_blocks = Vec::new(); let mut dropped_items = Vec::new(); self.clients.remove_if(|entity, client| { @@ -1003,7 +1002,13 @@ impl Server { .get(entity) .is_some() { - modified_blocks.push((pos, Block::empty())); + let block = state.terrain().get(pos).ok().copied(); + + if state.try_set_block(pos, Block::empty()).is_some() { + block + .and_then(|block| comp::Item::try_reclaim_from_block(block)) + .map(|item| state.give_item(entity, item)); + } } } ClientMsg::PlaceBlock(pos, block) => { @@ -1013,7 +1018,7 @@ impl Server { .get(entity) .is_some() { - modified_blocks.push((pos, block)); + state.try_set_block(pos, block); } } ClientMsg::TerrainChunkRequest { key } => match client.client_state { @@ -1117,10 +1122,6 @@ impl Server { self.generate_chunk(entity, key); } - for (pos, block) in modified_blocks { - self.state.set_block(pos, block); - } - for (pos, ori, item) in dropped_items { let vel = ori.0.normalized() * 5.0 + Vec3::unit_z() * 10.0 @@ -1384,3 +1385,17 @@ impl Drop for Server { self.clients.notify_registered(ServerMsg::Shutdown); } } + +trait StateExt { + fn give_item(&mut self, entity: EcsEntity, item: comp::Item); +} + +impl StateExt for State { + fn give_item(&mut self, entity: EcsEntity, item: comp::Item) { + self.ecs() + .write_storage::() + .get_mut(entity) + .map(|inv| inv.push(item)); + self.write_component(entity, comp::InventoryUpdate); + } +} diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index 9e9f216e5b..67796b5b67 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -144,7 +144,10 @@ impl PlayState for SessionState { { let (d, b) = { let terrain = client.state().terrain(); - let ray = terrain.ray(cam_pos, cam_pos + cam_dir * 100.0).cast(); + let ray = terrain + .ray(cam_pos, cam_pos + cam_dir * 100.0) + .until(|block| !block.is_air()) + .cast(); (ray.0, if let Ok(Some(_)) = ray.1 { true } else { false }) }; @@ -169,7 +172,10 @@ impl PlayState for SessionState { { let (d, b) = { let terrain = client.state().terrain(); - let ray = terrain.ray(cam_pos, cam_pos + cam_dir * 100.0).cast(); + let ray = terrain + .ray(cam_pos, cam_pos + cam_dir * 100.0) + .until(|block| block.is_tangeable()) + .cast(); (ray.0, if let Ok(Some(_)) = ray.1 { true } else { false }) }; diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 4364f5f8c4..7482575993 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -437,7 +437,7 @@ impl<'a> ZCache<'a> { } }); - let ground_max = (self.sample.alt + 2.0 + warp + rocks).max(cliff); + let ground_max = (self.sample.alt + 3.0 + warp + rocks).max(cliff); let min = min + structure_min; let max = (ground_max + structure_max)