1
1
use base:: { ItemStack , ValidBlockPosition } ;
2
2
use ecs:: { EntityBuilder , SysResult , SystemExecutor } ;
3
3
use libcraft_items:: EnchantmentKind ;
4
- use quill_common:: entity_init:: EntityInit ;
4
+ use quill_common:: { entities :: Player , entity_init:: EntityInit } ;
5
5
6
6
pub struct DestroyStateChange ( pub ValidBlockPosition , pub u8 ) ;
7
7
8
8
use crate :: { Game , World } ;
9
9
10
- pub type BlockBreaker = Option < ActiveBlockBreaker > ;
11
- #[ derive( Clone , Copy ) ]
12
- pub struct ActiveBlockBreaker {
13
- pub position : ValidBlockPosition ,
14
- pub drop_item : bool ,
15
- pub total_ticks : u32 ,
16
- pub ticks_remaining : u32 ,
10
+ #[ derive( Clone ) ]
11
+ pub enum BlockBreaker {
12
+ Active ( ActiveBreaker ) ,
13
+ Finished ( FinishedBreaker ) ,
14
+ Inactive ,
17
15
}
18
- impl ActiveBlockBreaker {
16
+ impl BlockBreaker {
17
+ pub fn new (
18
+ world : & mut World ,
19
+ block_pos : ValidBlockPosition ,
20
+ equipped_item : Option < & ItemStack > ,
21
+ ) -> Self {
22
+ ActiveBreaker :: new ( world, block_pos, equipped_item)
23
+ . map ( Self :: Active )
24
+ . unwrap_or ( Self :: Inactive )
25
+ }
26
+ pub fn destroy_change_event ( & self ) -> Option < DestroyStateChange > {
27
+ Some ( DestroyStateChange ( self . position ( ) ?, self . destroy_stage ( ) ) )
28
+ }
29
+ pub fn position ( & self ) -> Option < ValidBlockPosition > {
30
+ match self {
31
+ BlockBreaker :: Active ( a) => Some ( a. position ) ,
32
+ BlockBreaker :: Finished ( f) => Some ( f. position ) ,
33
+ BlockBreaker :: Inactive => None ,
34
+ }
35
+ }
36
+ pub fn active ( & self ) -> Option < & ActiveBreaker > {
37
+ match self {
38
+ Self :: Active ( a) => Some ( a) ,
39
+ _ => None ,
40
+ }
41
+ }
42
+ pub fn finished ( & self ) -> Option < & FinishedBreaker > {
43
+ match self {
44
+ Self :: Finished ( f) => Some ( f) ,
45
+ _ => None ,
46
+ }
47
+ }
19
48
pub fn tick ( & mut self ) -> ( bool , bool ) {
20
- let before = self . destroy_stage ( ) ;
21
- self . ticks_remaining = self . ticks_remaining . saturating_sub ( 1 ) ;
22
- let after = self . destroy_stage ( ) ;
23
- ( self . ticks_remaining == 0 , before != after)
49
+ let ( block_break, stage_update) = if let Self :: Active ( breaker) = self {
50
+ breaker. tick ( )
51
+ } else {
52
+ ( false , false )
53
+ } ;
54
+ if block_break {
55
+ let fin = match self {
56
+ Self :: Active ( a) => a. clone ( ) . finish ( ) ,
57
+ _ => unreachable ! ( ) ,
58
+ } ;
59
+ * self = Self :: Finished ( fin) ;
60
+ }
61
+ ( block_break, stage_update)
24
62
}
25
- pub fn break_block ( self , game : & mut Game ) -> SysResult {
63
+ pub fn destroy_stage ( & self ) -> u8 {
64
+ match self {
65
+ BlockBreaker :: Active ( a) => a. destroy_stage ( ) ,
66
+ _ => 10 ,
67
+ }
68
+ }
69
+ pub fn cancel ( & mut self ) {
70
+ * self = Self :: Inactive ;
71
+ }
72
+ pub fn matches_position ( & self , pos : ValidBlockPosition ) -> bool {
73
+ match self {
74
+ BlockBreaker :: Active ( a) => a. position == pos,
75
+ BlockBreaker :: Finished ( f) => f. position == pos,
76
+ BlockBreaker :: Inactive => true ,
77
+ }
78
+ }
79
+ pub fn try_finish ( & mut self ) -> Option < FinishedBreaker > {
80
+ let this = self . clone ( ) ;
81
+ match this {
82
+ BlockBreaker :: Active ( a) => {
83
+ if a. ticks_remaining == 1 {
84
+ let fin = a. finish ( ) ;
85
+ * self = Self :: Finished ( fin. clone ( ) ) ;
86
+ Some ( fin)
87
+ } else {
88
+ None
89
+ }
90
+ }
91
+ BlockBreaker :: Finished ( f) => Some ( f) ,
92
+ BlockBreaker :: Inactive => None ,
93
+ }
94
+ }
95
+ }
96
+ #[ derive( Clone ) ]
97
+ pub struct FinishedBreaker {
98
+ pub position : ValidBlockPosition ,
99
+ pub drop_item : bool ,
100
+ pub fake_finished : bool ,
101
+ }
102
+ impl FinishedBreaker {
103
+ pub fn break_block ( & self , game : & mut Game ) -> SysResult {
26
104
let target_block = match game. block ( self . position ) {
27
105
Some ( b) => b,
28
106
None => anyhow:: bail!( "cannot break unloaded block" ) ,
@@ -39,16 +117,34 @@ impl ActiveBlockBreaker {
39
117
}
40
118
Ok ( ( ) )
41
119
}
42
- pub fn new_player (
120
+ }
121
+ #[ derive( Clone ) ]
122
+ pub struct ActiveBreaker {
123
+ pub position : ValidBlockPosition ,
124
+ pub drop_item : bool ,
125
+ pub fake_finished : bool ,
126
+ pub total_ticks : u32 ,
127
+ pub ticks_remaining : u32 ,
128
+ }
129
+ impl ActiveBreaker {
130
+ pub fn tick ( & mut self ) -> ( bool , bool ) {
131
+ let before = self . destroy_stage ( ) ;
132
+ self . ticks_remaining = self . ticks_remaining . saturating_sub ( 1 ) ;
133
+ let after = self . destroy_stage ( ) ;
134
+ let break_block = self . ticks_remaining == 0 ;
135
+ let change_stage = before != after || break_block;
136
+ ( break_block, change_stage)
137
+ }
138
+ pub fn new (
43
139
world : & mut World ,
44
140
block_pos : ValidBlockPosition ,
45
- main_hand : Option < & ItemStack > ,
141
+ equipped_item : Option < & ItemStack > ,
46
142
) -> Option < Self > {
47
143
let block = world. block_at ( block_pos) ?. kind ( ) ;
48
144
if !block. diggable ( ) {
49
145
return None ;
50
146
}
51
- let harvestable = match ( block. harvest_tools ( ) , main_hand ) {
147
+ let harvestable = match ( block. harvest_tools ( ) , equipped_item ) {
52
148
( None , None | Some ( _) ) => true ,
53
149
( Some ( _) , None ) => false ,
54
150
( Some ( tools) , Some ( tool) ) => tools. contains ( & tool. item ( ) ) ,
@@ -57,7 +153,7 @@ impl ActiveBlockBreaker {
57
153
. dig_multipliers ( )
58
154
. iter ( )
59
155
. find_map ( |( item, speed) | {
60
- main_hand
156
+ equipped_item
61
157
. map ( |e| {
62
158
if e. item ( ) == * item {
63
159
Some ( * speed)
@@ -68,7 +164,7 @@ impl ActiveBlockBreaker {
68
164
. flatten ( )
69
165
} )
70
166
. unwrap_or ( 1.0 ) ;
71
- let effi_level = main_hand
167
+ let effi_level = equipped_item
72
168
. map ( ItemStack :: metadata)
73
169
. flatten ( )
74
170
. map ( |meta| {
@@ -90,17 +186,37 @@ impl ActiveBlockBreaker {
90
186
let ticks = if damage > 1.0 {
91
187
0
92
188
} else {
93
- ( 1.0 / damage) . ceil ( ) as u32 - 4
189
+ ( 1.0 / damage / 1.2 ) . ceil ( ) as u32
94
190
} ;
191
+ println ! (
192
+ "Mining {} with {} takes {} ticks" ,
193
+ block. display_name( ) ,
194
+ equipped_item
195
+ . map( |e| e. get_item( ) . item( ) . display_name( ) )
196
+ . unwrap_or( "bare hands" ) ,
197
+ ticks
198
+ ) ;
95
199
Some ( Self {
96
200
position : block_pos,
97
201
drop_item : true ,
202
+ fake_finished : false ,
98
203
total_ticks : ticks,
99
204
ticks_remaining : ticks,
100
205
} )
101
206
}
102
207
pub fn destroy_stage ( & self ) -> u8 {
103
- 9 - ( self . ticks_remaining as f32 / self . total_ticks as f32 * 9.0 ) . round ( ) as u8
208
+ if self . fake_finished {
209
+ 10
210
+ } else {
211
+ 9 - ( self . ticks_remaining as f32 / self . total_ticks as f32 * 9.0 ) . round ( ) as u8
212
+ }
213
+ }
214
+ pub fn finish ( self ) -> FinishedBreaker {
215
+ FinishedBreaker {
216
+ position : self . position ,
217
+ drop_item : self . drop_item ,
218
+ fake_finished : self . fake_finished ,
219
+ }
104
220
}
105
221
}
106
222
@@ -112,35 +228,28 @@ fn process_block_breaking(game: &mut Game) -> SysResult {
112
228
let mut break_queue = vec ! [ ] ;
113
229
let mut update_queue = vec ! [ ] ;
114
230
for ( entity, breaker) in game. ecs . query :: < & mut BlockBreaker > ( ) . iter ( ) {
115
- if let Some ( active) = breaker {
116
- let ( break_block, update_stage) = active. tick ( ) ;
117
- if update_stage {
118
- update_queue. push ( entity) ;
119
- }
120
- if break_block {
231
+ let ( break_block, update_stage) = breaker. tick ( ) ;
232
+ if update_stage {
233
+ update_queue. push ( entity) ;
234
+ }
235
+ // Break block when client requests to finish in order to prevent desyncs
236
+ if break_block {
237
+ if breaker. finished ( ) . unwrap ( ) . fake_finished || !game. ecs . get :: < Player > ( entity) . is_ok ( )
238
+ {
121
239
break_queue. push ( entity) ;
122
240
}
123
241
}
124
242
}
125
243
for entity in update_queue {
126
- let breaker = { game. ecs . get_mut :: < BlockBreaker > ( entity) . unwrap ( ) . unwrap ( ) } ;
127
- game. ecs . insert_entity_event (
128
- entity,
129
- DestroyStateChange ( breaker. position , breaker. destroy_stage ( ) ) ,
130
- ) ?;
244
+ let event = game
245
+ . ecs
246
+ . get_mut :: < BlockBreaker > ( entity) ?
247
+ . destroy_change_event ( )
248
+ . unwrap ( ) ;
249
+ game. ecs . insert_entity_event ( entity, event) ?;
131
250
}
132
251
for entity in break_queue. into_iter ( ) {
133
- // Set block breakers to None
134
- let breaker = {
135
- game. ecs
136
- . get_mut :: < BlockBreaker > ( entity)
137
- . unwrap ( )
138
- . take ( )
139
- . unwrap ( )
140
- } ;
141
- game. ecs
142
- . insert_entity_event ( entity, DestroyStateChange ( breaker. position , 10 ) )
143
- . unwrap ( ) ;
252
+ let breaker = game. ecs . get :: < BlockBreaker > ( entity) ?. finished ( ) . unwrap ( ) . clone ( ) ;
144
253
breaker. break_block ( game) ?;
145
254
}
146
255
Ok ( ( ) )
0 commit comments