@@ -5,6 +5,7 @@ use ferrumc_core::transform::grounded::OnGround;
5
5
use ferrumc_core:: transform:: position:: Position ;
6
6
use ferrumc_core:: transform:: rotation:: Rotation ;
7
7
use ferrumc_ecs:: components:: storage:: ComponentRefMut ;
8
+ use ferrumc_ecs:: entities:: Entity ;
8
9
use ferrumc_macros:: event_handler;
9
10
use ferrumc_net:: connection:: { ConnectionState , StreamWriter } ;
10
11
use ferrumc_net:: errors:: NetError ;
@@ -20,13 +21,19 @@ use ferrumc_net::packets::outgoing::keep_alive::OutgoingKeepAlivePacket;
20
21
use ferrumc_net:: packets:: outgoing:: login_disconnect:: LoginDisconnectPacket ;
21
22
use ferrumc_net:: packets:: outgoing:: login_play:: LoginPlayPacket ;
22
23
use ferrumc_net:: packets:: outgoing:: login_success:: LoginSuccessPacket ;
24
+ use ferrumc_net:: packets:: outgoing:: player_info_update:: PlayerInfoUpdatePacket ;
23
25
use ferrumc_net:: packets:: outgoing:: registry_data:: get_registry_packets;
24
26
use ferrumc_net:: packets:: outgoing:: set_center_chunk:: SetCenterChunk ;
25
27
use ferrumc_net:: packets:: outgoing:: set_default_spawn_position:: SetDefaultSpawnPositionPacket ;
26
28
use ferrumc_net:: packets:: outgoing:: set_render_distance:: SetRenderDistance ;
29
+ use ferrumc_net:: packets:: outgoing:: spawn_entity:: SpawnEntityPacket ;
27
30
use ferrumc_net:: packets:: outgoing:: synchronize_player_position:: SynchronizePlayerPositionPacket ;
31
+ use ferrumc_net:: utils:: broadcast:: { broadcast, get_all_play_players, BroadcastOptions } ;
32
+ use ferrumc_net:: NetResult ;
28
33
use ferrumc_net_codec:: encode:: NetEncodeOpts ;
29
34
use ferrumc_state:: GlobalState ;
35
+ use futures:: StreamExt ;
36
+ use std:: time:: Instant ;
30
37
use tracing:: { debug, trace} ;
31
38
32
39
#[ event_handler]
@@ -46,7 +53,7 @@ async fn handle_login_start(
46
53
login_start_event. conn_id ,
47
54
PlayerIdentity :: new ( username. to_string ( ) , uuid) ,
48
55
) ?
49
- . add_component :: < ChunkReceiver > ( login_start_event. conn_id , ChunkReceiver :: default ( ) ) ?;
56
+ /* .add_component::<ChunkReceiver>(login_start_event.conn_id, ChunkReceiver::default())?*/ ;
50
57
51
58
//Send a Login Success Response to further the login sequence
52
59
let mut writer = state
@@ -145,69 +152,73 @@ async fn handle_ack_finish_configuration(
145
152
state : GlobalState ,
146
153
) -> Result < AckFinishConfigurationEvent , NetError > {
147
154
trace ! ( "Handling Ack Finish Configuration event" ) ;
155
+ let entity_id = ack_finish_configuration_event. conn_id ;
156
+ {
157
+ let mut conn_state = state. universe . get_mut :: < ConnectionState > ( entity_id) ?;
158
+
159
+ * conn_state = ConnectionState :: Play ;
160
+
161
+ // add components to the entity after the connection state has been set to play.
162
+ // to avoid wasting resources on entities that are fetching stuff like server status etc.
163
+ state
164
+ . universe
165
+ . add_component :: < Position > ( entity_id, Position :: default ( ) ) ?
166
+ . add_component :: < Rotation > ( entity_id, Rotation :: default ( ) ) ?
167
+ . add_component :: < OnGround > ( entity_id, OnGround :: default ( ) ) ?
168
+ . add_component :: < ChunkReceiver > ( entity_id, ChunkReceiver :: default ( ) ) ?;
169
+
170
+ let mut writer = state. universe . get_mut :: < StreamWriter > ( entity_id) ?;
171
+
172
+ writer // 21
173
+ . send_packet ( & LoginPlayPacket :: new ( entity_id) , & NetEncodeOpts :: WithLength )
174
+ . await ?;
175
+ writer // 29
176
+ . send_packet (
177
+ & SynchronizePlayerPositionPacket :: default ( ) , // The coordinates here should be used for the center chunk.
178
+ & NetEncodeOpts :: WithLength ,
179
+ )
180
+ . await ?;
181
+ writer // 37
182
+ . send_packet (
183
+ & SetDefaultSpawnPositionPacket :: default ( ) , // Player specific, aka. home, bed, where it would respawn.
184
+ & NetEncodeOpts :: WithLength ,
185
+ )
186
+ . await ?;
187
+ writer // 38
188
+ . send_packet (
189
+ & GameEventPacket :: start_waiting_for_level_chunks ( ) ,
190
+ & NetEncodeOpts :: WithLength ,
191
+ )
192
+ . await ?;
193
+ writer // 41
194
+ . send_packet (
195
+ & SetCenterChunk :: new ( 0 , 0 ) , // TODO - Dependent on the player spawn position.
196
+ & NetEncodeOpts :: WithLength ,
197
+ )
198
+ . await ?;
199
+ writer // other
200
+ . send_packet (
201
+ & SetRenderDistance :: new ( 5 ) , // TODO
202
+ & NetEncodeOpts :: WithLength ,
203
+ )
204
+ . await ?;
205
+
206
+ send_keep_alive ( entity_id, & state, & mut writer) . await ?;
207
+
208
+ let pos = state. universe . get_mut :: < Position > ( entity_id) ?;
209
+ let mut chunk_recv = state. universe . get_mut :: < ChunkReceiver > ( entity_id) ?;
210
+ chunk_recv. last_chunk = Some ( ( pos. x as i32 , pos. z as i32 , String :: from ( "overworld" ) ) ) ;
211
+ chunk_recv. calculate_chunks ( ) . await ;
212
+ }
148
213
149
- let conn_id = ack_finish_configuration_event. conn_id ;
150
-
151
- let mut conn_state = state. universe . get_mut :: < ConnectionState > ( conn_id) ?;
152
-
153
- * conn_state = ConnectionState :: Play ;
154
-
155
- // add components to the entity after the connection state has been set to play.
156
- // to avoid wasting resources on entities that are fetching stuff like server status etc.
157
- state
158
- . universe
159
- . add_component :: < Position > ( conn_id, Position :: default ( ) ) ?
160
- . add_component :: < Rotation > ( conn_id, Rotation :: default ( ) ) ?
161
- . add_component :: < OnGround > ( conn_id, OnGround :: default ( ) ) ?;
162
-
163
- let mut writer = state. universe . get_mut :: < StreamWriter > ( conn_id) ?;
164
-
165
- writer // 21
166
- . send_packet ( & LoginPlayPacket :: new ( conn_id) , & NetEncodeOpts :: WithLength )
167
- . await ?;
168
- writer // 29
169
- . send_packet (
170
- & SynchronizePlayerPositionPacket :: default ( ) , // The coordinates here should be used for the center chunk.
171
- & NetEncodeOpts :: WithLength ,
172
- )
173
- . await ?;
174
- writer // 37
175
- . send_packet (
176
- & SetDefaultSpawnPositionPacket :: default ( ) , // Player specific, aka. home, bed, where it would respawn.
177
- & NetEncodeOpts :: WithLength ,
178
- )
179
- . await ?;
180
- writer // 38
181
- . send_packet (
182
- & GameEventPacket :: start_waiting_for_level_chunks ( ) ,
183
- & NetEncodeOpts :: WithLength ,
184
- )
185
- . await ?;
186
- writer // 41
187
- . send_packet (
188
- & SetCenterChunk :: new ( 0 , 0 ) , // TODO - Dependent on the player spawn position.
189
- & NetEncodeOpts :: WithLength ,
190
- )
191
- . await ?;
192
- writer // other
193
- . send_packet (
194
- & SetRenderDistance :: new ( 5 ) , // TODO
195
- & NetEncodeOpts :: WithLength ,
196
- )
197
- . await ?;
198
-
199
- let pos = state. universe . get_mut :: < Position > ( conn_id) ?;
200
- let mut chunk_recv = state. universe . get_mut :: < ChunkReceiver > ( conn_id) ?;
201
- chunk_recv. last_chunk = Some ( ( pos. x as i32 , pos. z as i32 , String :: from ( "overworld" ) ) ) ;
202
- chunk_recv. calculate_chunks ( ) . await ;
203
-
204
- send_keep_alive ( conn_id, state, & mut writer) . await ?;
214
+ player_info_update_packets ( entity_id, & state) . await ?;
215
+ broadcast_spawn_entity_packet ( entity_id, & state) . await ?;
205
216
206
217
Ok ( ack_finish_configuration_event)
207
218
}
208
219
async fn send_keep_alive (
209
220
conn_id : usize ,
210
- state : GlobalState ,
221
+ state : & GlobalState ,
211
222
writer : & mut ComponentRefMut < ' _ , StreamWriter > ,
212
223
) -> Result < ( ) , NetError > {
213
224
let keep_alive_packet = OutgoingKeepAlivePacket :: default ( ) ;
@@ -226,3 +237,63 @@ async fn send_keep_alive(
226
237
227
238
Ok ( ( ) )
228
239
}
240
+
241
+ async fn player_info_update_packets ( entity_id : Entity , state : & GlobalState ) -> NetResult < ( ) > {
242
+ // Broadcasts a player info update packet to all players.
243
+ {
244
+ let packet = PlayerInfoUpdatePacket :: new_player_join_packet ( entity_id, state) ;
245
+
246
+ let start = Instant :: now ( ) ;
247
+ broadcast (
248
+ & packet,
249
+ state,
250
+ BroadcastOptions :: default ( ) . except ( [ entity_id] ) ,
251
+ )
252
+ . await ?;
253
+ trace ! (
254
+ "Broadcasting player info update took: {:?}" ,
255
+ start. elapsed( )
256
+ ) ;
257
+ }
258
+
259
+ // Tell the player about all the other players that are already connected.
260
+ {
261
+ let packet = PlayerInfoUpdatePacket :: existing_player_info_packet ( entity_id, state) ;
262
+
263
+ let start = Instant :: now ( ) ;
264
+ let mut writer = state. universe . get_mut :: < StreamWriter > ( entity_id) ?;
265
+ writer
266
+ . send_packet ( & packet, & NetEncodeOpts :: WithLength )
267
+ . await ?;
268
+ debug ! ( "Sending player info update took: {:?}" , start. elapsed( ) ) ;
269
+ }
270
+
271
+ Ok ( ( ) )
272
+ }
273
+
274
+ async fn broadcast_spawn_entity_packet ( entity_id : Entity , state : & GlobalState ) -> NetResult < ( ) > {
275
+ let packet = SpawnEntityPacket :: player ( entity_id, state) ?;
276
+
277
+ let start = Instant :: now ( ) ;
278
+ broadcast (
279
+ & packet,
280
+ state,
281
+ BroadcastOptions :: default ( ) . except ( [ entity_id] ) ,
282
+ )
283
+ . await ?;
284
+ trace ! ( "Broadcasting spawn entity took: {:?}" , start. elapsed( ) ) ;
285
+
286
+ let writer = state. universe . get_mut :: < StreamWriter > ( entity_id) ?;
287
+ futures:: stream:: iter ( get_all_play_players ( state) )
288
+ . fold ( writer, |mut writer, entity| async move {
289
+ if let Ok ( packet) = SpawnEntityPacket :: player ( entity, state) {
290
+ let _ = writer
291
+ . send_packet ( & packet, & NetEncodeOpts :: WithLength )
292
+ . await ;
293
+ }
294
+ writer
295
+ } )
296
+ . await ;
297
+
298
+ Ok ( ( ) )
299
+ }
0 commit comments