Use try_set for door destruction to avoid accidentally overwriting any

other changes that already occured that tick.

Also get terrain/block change resources from the ecs once to avoid the
overhead of fetching them from the ecs (and aquiring/releasing runtime
borrow).
This commit is contained in:
Imbris 2023-03-10 21:52:14 -05:00
parent 3ad9297623
commit 619f62cb63
2 changed files with 23 additions and 20 deletions

View File

@ -68,6 +68,10 @@ impl BlockChange {
}
}
/// Check if the block at given position `pos` has already been modified
/// this tick.
pub fn can_set_block(&self, pos: Vec3<i32>) -> bool { !self.blocks.contains_key(&pos) }
pub fn clear(&mut self) { self.blocks.clear(); }
}
@ -461,11 +465,7 @@ impl State {
/// Check if the block at given position `pos` has already been modified
/// this tick.
pub fn can_set_block(&self, pos: Vec3<i32>) -> bool {
!self
.ecs
.read_resource::<BlockChange>()
.blocks
.contains_key(&pos)
self.ecs.read_resource::<BlockChange>().can_set_block(pos)
}
/// Removes every chunk of the terrain.

View File

@ -252,17 +252,21 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
sprite_pos,
required_item,
} => {
let block = state.terrain().get(sprite_pos).ok().copied();
let ecs = state.ecs();
let terrain = ecs.read_resource::<common::terrain::TerrainGrid>();
let mut block_change = ecs.write_resource::<common_state::BlockChange>();
let block = terrain.get(sprite_pos).ok().copied();
let mut drop_item = None;
if let Some(block) = block {
if block.is_collectible() && state.can_set_block(sprite_pos) {
if block.is_collectible() && block_change.can_set_block(sprite_pos) {
// If an item was required to collect the sprite, consume it now
if let Some((inv_slot, true)) = required_item {
inventory.take(
inv_slot,
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<MaterialStatManifest>(),
&ecs.read_resource::<AbilityMap>(),
&ecs.read_resource::<MaterialStatManifest>(),
);
}
@ -270,20 +274,19 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
if let Some(item) = comp::Item::try_reclaim_from_block(block) {
// NOTE: We dup the item for message purposes.
let item_msg = item.duplicate(
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<MaterialStatManifest>(),
&ecs.read_resource::<AbilityMap>(),
&ecs.read_resource::<MaterialStatManifest>(),
);
let event = match inventory.push(item) {
Ok(_) => {
let ecs = state.ecs();
if let Some(group_id) = ecs.read_storage::<Group>().get(entity) {
announce_loot_to_group(
group_id,
ecs,
entity,
item_msg.duplicate(
&state.ecs().read_resource::<AbilityMap>(),
&state.ecs().read_resource::<MaterialStatManifest>(),
&ecs.read_resource::<AbilityMap>(),
&ecs.read_resource::<MaterialStatManifest>(),
),
);
}
@ -303,15 +306,13 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
)
},
};
state
.ecs()
.write_storage()
ecs.write_storage()
.insert(entity, event)
.expect("We know entity exists since we got its inventory.");
}
// We made sure earlier the block was not already modified this tick
state.set_block(sprite_pos, block.into_vacant());
block_change.set(sprite_pos, block.into_vacant());
// If the block was a keyhole, remove nearby door blocks
// TODO: Abstract this code into a generalised way to do block updates?
@ -339,11 +340,11 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
pending.remove(&pos);
if !destroyed.contains(&pos)
&& matches!(
state.terrain().get(pos).ok().and_then(|b| b.get_sprite()),
terrain.get(pos).ok().and_then(|b| b.get_sprite()),
Some(SpriteKind::KeyDoor)
)
{
state.set_block(pos, Block::empty());
block_change.try_set(pos, Block::empty());
destroyed.insert(pos);
pending.extend(dirs.into_iter().map(|dir| pos + dir));
@ -362,6 +363,8 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
}
}
drop(inventories);
drop(terrain);
drop(block_change);
if let Some(item) = drop_item {
state
.create_item_drop(Default::default(), item)