Skip to content

Commit 3e5d7e8

Browse files
committed
Block breaking progress sent to client
1 parent cb6c3f6 commit 3e5d7e8

File tree

4 files changed

+116
-29
lines changed

4 files changed

+116
-29
lines changed

feather/common/src/block_break.rs

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,35 @@
1-
use base::{ValidBlockPosition, ItemStack};
2-
use ecs::{SystemExecutor, SysResult, EntityBuilder};
1+
use base::{ItemStack, ValidBlockPosition};
2+
use ecs::{EntityBuilder, SysResult, SystemExecutor};
33
use quill_common::entity_init::EntityInit;
44

5+
pub struct DestroyStateChange(pub ValidBlockPosition, pub u8);
6+
57
use crate::{Game, World};
68

79
pub type BlockBreaker = Option<ActiveBlockBreaker>;
10+
#[derive(Clone, Copy)]
811
pub struct ActiveBlockBreaker {
912
pub position: ValidBlockPosition,
1013
pub drop_item: bool,
14+
pub total_ticks: u32,
1115
pub ticks_remaining: u32,
1216
}
1317
impl ActiveBlockBreaker {
14-
pub fn tick(&mut self) -> bool {
18+
pub fn tick(&mut self) -> (bool, bool) {
19+
let before = self.destroy_stage();
1520
self.ticks_remaining = self.ticks_remaining.saturating_sub(1);
16-
self.ticks_remaining == 0
21+
let after = self.destroy_stage();
22+
(self.ticks_remaining == 0, before != after)
1723
}
1824
pub fn break_block(self, game: &mut Game) -> SysResult {
1925
let target_block = match game.block(self.position) {
2026
Some(b) => b,
21-
None => anyhow::bail!("cannot break unloaded block")
27+
None => anyhow::bail!("cannot break unloaded block"),
2228
};
2329
game.break_block(self.position);
2430
if let Some(_item_drop) = base::Item::from_name(target_block.kind().name()) {
2531
if !self.drop_item {
26-
return Ok(())
32+
return Ok(());
2733
}
2834
let mut item_entity = EntityBuilder::new();
2935
crate::entities::item::build_default(&mut item_entity);
@@ -32,35 +38,63 @@ impl ActiveBlockBreaker {
3238
}
3339
Ok(())
3440
}
35-
pub fn new_player(_world: &mut World, block_pos: ValidBlockPosition, _mainhand: Option<&ItemStack>, _offhand: Option<&ItemStack>) -> Option<Self> {
41+
pub fn new_player(
42+
_world: &mut World,
43+
block_pos: ValidBlockPosition,
44+
_mainhand: Option<&ItemStack>,
45+
_offhand: Option<&ItemStack>,
46+
) -> Option<Self> {
3647
// TODO
3748
Some(Self {
3849
position: block_pos,
3950
drop_item: true,
51+
total_ticks: 20,
4052
ticks_remaining: 20,
4153
})
4254
}
55+
pub fn destroy_stage(&self) -> u8 {
56+
9 - (self.ticks_remaining as f32 / self.total_ticks as f32 * 9.0).round() as u8
57+
}
4358
}
4459

4560
pub fn register(systems: &mut SystemExecutor<Game>) {
4661
systems.add_system(process_block_breaking);
4762
}
4863

4964
fn process_block_breaking(game: &mut Game) -> SysResult {
50-
let mut break_queue = vec![];
65+
let mut break_queue = vec![];
66+
let mut update_queue = vec![];
5167
for (entity, breaker) in game.ecs.query::<&mut BlockBreaker>().iter() {
5268
if let Some(active) = breaker {
53-
if active.tick() {
69+
let (break_block, update_stage) = active.tick();
70+
if update_stage {
71+
update_queue.push(entity);
72+
}
73+
if break_block {
5474
break_queue.push(entity);
5575
}
5676
}
5777
}
78+
for entity in update_queue {
79+
let breaker = { game.ecs.get_mut::<BlockBreaker>(entity).unwrap().unwrap() };
80+
game.ecs.insert_entity_event(
81+
entity,
82+
DestroyStateChange(breaker.position, breaker.destroy_stage()),
83+
)?;
84+
}
5885
for entity in break_queue.into_iter() {
5986
// Set block breakers to None
6087
let breaker = {
61-
game.ecs.get_mut::<BlockBreaker>(entity)?.take().unwrap()
88+
game.ecs
89+
.get_mut::<BlockBreaker>(entity)
90+
.unwrap()
91+
.take()
92+
.unwrap()
6293
};
94+
game.ecs
95+
.insert_entity_event(entity, DestroyStateChange(breaker.position, 10))
96+
.unwrap();
6397
breaker.break_block(game)?;
6498
}
6599
Ok(())
66-
}
100+
}

feather/server/src/client.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ use common::{
2020
use libcraft_items::InventorySlot;
2121
use packets::server::{Particle, SetSlot, SpawnLivingEntity, UpdateLight, WindowConfirmation};
2222
use protocol::packets::server::{
23-
EntityPosition, EntityPositionAndRotation, EntityTeleport, HeldItemChange, PlayerAbilities, PlayerDiggingStatus, AcknowledgePlayerDigging, BlockBreakAnimation,
23+
AcknowledgePlayerDigging, BlockBreakAnimation, EntityPosition, EntityPositionAndRotation,
24+
EntityTeleport, HeldItemChange, PlayerAbilities, PlayerDiggingStatus,
2425
};
2526
use protocol::{
2627
packets::{
@@ -602,7 +603,13 @@ impl Client {
602603
self.send_packet(HeldItemChange { slot });
603604
}
604605

605-
pub fn acknowledge_player_digging(&self, position: ValidBlockPosition, block: BlockId, status: PlayerDiggingStatus, successful: bool) {
606+
pub fn acknowledge_player_digging(
607+
&self,
608+
position: ValidBlockPosition,
609+
block: BlockId,
610+
status: PlayerDiggingStatus,
611+
successful: bool,
612+
) {
606613
self.send_packet(AcknowledgePlayerDigging {
607614
position,
608615
block,
@@ -611,9 +618,14 @@ impl Client {
611618
})
612619
}
613620

614-
pub fn block_break_animation(&self, entity_id: i32, position: ValidBlockPosition, destroy_stage: u8) {
621+
pub fn block_break_animation(
622+
&self,
623+
entity_id: u32,
624+
position: ValidBlockPosition,
625+
destroy_stage: u8,
626+
) {
615627
self.send_packet(BlockBreakAnimation {
616-
entity_id,
628+
entity_id: i32::from_le_bytes(entity_id.to_le_bytes()),
617629
position,
618630
destroy_stage,
619631
})

feather/server/src/packet_handlers/interaction.rs

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{ClientId, NetworkId, Server};
2-
use base::Gamemode;
32
use base::inventory::{SLOT_HOTBAR_OFFSET, SLOT_OFFHAND};
4-
use common::block_break::{BlockBreaker, ActiveBlockBreaker};
3+
use base::Gamemode;
4+
use common::block_break::{ActiveBlockBreaker, BlockBreaker, DestroyStateChange};
55
use common::entities::player::HotbarSlot;
66
use common::interactable::InteractableRegistry;
77
use common::{Game, Window};
@@ -122,31 +122,63 @@ pub fn handle_player_digging(
122122
log::trace!("Got player digging with status {:?}", packet.status);
123123
match packet.status {
124124
PlayerDiggingStatus::StartDigging => {
125-
if matches!(*game.ecs.get::<Gamemode>(player)?, Gamemode::Creative | Gamemode::Spectator) {
125+
if matches!(
126+
*game.ecs.get::<Gamemode>(player)?,
127+
Gamemode::Creative | Gamemode::Spectator
128+
) {
126129
game.break_block(packet.position);
127130
} else {
128131
let mut breaker = game.ecs.get_mut::<BlockBreaker>(player)?;
129132
let window = game.ecs.get::<Window>(player)?;
130133
let hotbar_slot = game.ecs.get::<HotbarSlot>(player)?.get();
131134
let main = window.item(SLOT_HOTBAR_OFFSET + hotbar_slot)?;
132135
let offh = window.item(SLOT_OFFHAND)?;
133-
let _ = breaker.insert(ActiveBlockBreaker::new_player(&mut game.world, packet.position, main.item_stack(), offh.item_stack()).unwrap());
136+
let _ = breaker.insert(
137+
ActiveBlockBreaker::new_player(
138+
&mut game.world,
139+
packet.position,
140+
main.item_stack(),
141+
offh.item_stack(),
142+
)
143+
.unwrap(),
144+
);
134145
}
135146

136147
Ok(())
137-
},
148+
}
138149
PlayerDiggingStatus::CancelDigging => {
139-
game.ecs.get_mut::<BlockBreaker>(player)?.take();
150+
let breaker = game.ecs.get_mut::<BlockBreaker>(player)?.take();
151+
if let Some(s) = breaker {
152+
game.ecs
153+
.insert_entity_event(player, DestroyStateChange(s.position, 10))?;
154+
}
155+
140156
let client = server.clients.get(*game.ecs.get(player)?).unwrap();
141-
let block = match game.block(packet.position) { Some(s)=>s,None=>return Ok(())};
142-
client.acknowledge_player_digging(packet.position, block, protocol::packets::server::PlayerDiggingStatus::Cancelled, false);
157+
let block = match game.block(packet.position) {
158+
Some(s) => s,
159+
None => return Ok(()),
160+
};
161+
client.acknowledge_player_digging(
162+
packet.position,
163+
block,
164+
protocol::packets::server::PlayerDiggingStatus::Cancelled,
165+
false,
166+
);
143167
Ok(())
144-
},
168+
}
145169
PlayerDiggingStatus::FinishDigging => {
146170
let success = game.ecs.get::<BlockBreaker>(player)?.is_some();
147171
let client = server.clients.get(*game.ecs.get(player)?).unwrap();
148-
let block = match game.block(packet.position) { Some(s)=>s,None=>return Ok(())};
149-
client.acknowledge_player_digging(packet.position, block, protocol::packets::server::PlayerDiggingStatus::Finished, success);
172+
let block = match game.block(packet.position) {
173+
Some(s) => s,
174+
None => return Ok(()),
175+
};
176+
client.acknowledge_player_digging(
177+
packet.position,
178+
block,
179+
protocol::packets::server::PlayerDiggingStatus::Finished,
180+
success,
181+
);
150182
Ok(())
151183
}
152184
PlayerDiggingStatus::SwapItemInHand => {
@@ -174,7 +206,6 @@ pub fn handle_player_digging(
174206
PlayerDiggingStatus::DropItemStack => Ok(()),
175207
PlayerDiggingStatus::DropItem => Ok(()),
176208
PlayerDiggingStatus::ShootArrow => Ok(()),
177-
178209
}
179210
}
180211

feather/server/src/systems/block.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,25 @@
1515
1616
use ahash::AHashMap;
1717
use base::{chunk::SECTION_VOLUME, position, ChunkPosition, CHUNK_WIDTH};
18-
use common::{events::BlockChangeEvent, Game};
18+
use common::{block_break::DestroyStateChange, events::BlockChangeEvent, Game};
1919
use ecs::{SysResult, SystemExecutor};
2020

2121
use crate::Server;
2222

2323
pub fn register(systems: &mut SystemExecutor<Game>) {
2424
systems
2525
.group::<Server>()
26-
.add_system(broadcast_block_changes);
26+
.add_system(broadcast_block_changes)
27+
.add_system(broadcast_block_destroy_stage_change);
28+
}
29+
30+
fn broadcast_block_destroy_stage_change(game: &mut Game, server: &mut Server) -> SysResult {
31+
for (entity, event) in game.ecs.query::<&DestroyStateChange>().iter() {
32+
server.broadcast_nearby_with(event.0.position(), |client| {
33+
client.block_break_animation(entity.id(), event.0, event.1);
34+
});
35+
}
36+
Ok(())
2737
}
2838

2939
fn broadcast_block_changes(game: &mut Game, server: &mut Server) -> SysResult {

0 commit comments

Comments
 (0)