@@ -460,20 +460,23 @@ fn apply_removals(
460460 message_tick : RepliconTick ,
461461) -> Result < ( ) > {
462462 let server_entity = postcard_utils:: entity_from_buf ( message) ?;
463+ let data_size: usize = postcard_utils:: from_buf ( message) ?;
463464
464- let mut client_entity = match params. entity_map . server_entry ( server_entity) {
465- EntityEntry :: Occupied ( entry) => {
466- DeferredEntity :: new ( world. get_entity_mut ( entry. get ( ) ) ?, params. changes )
467- }
468- EntityEntry :: Vacant ( entry) => {
469- // It's possible to receive a removal when an entity is spawned and has a component removed in the same tick.
470- // We could serialize the size of the removals instead of the total number of removals and just advance the cursor,
471- // but it's a very rare case and not worth optimizing for.
472- let mut client_entity = DeferredEntity :: new ( world. spawn_empty ( ) , params. changes ) ;
473- client_entity. insert ( Replicated ) ;
474- entry. insert ( client_entity. id ( ) ) ;
475- client_entity
476- }
465+ // Server never sends removals for entities that weren't received by the client.
466+ let client_entity = * params
467+ . entity_map
468+ . to_client ( )
469+ . get ( & server_entity)
470+ . ok_or_else ( || format ! ( "received removal for unknown server's `{server_entity}`" ) ) ?;
471+
472+ let Ok ( mut client_entity) = world
473+ . get_entity_mut ( client_entity)
474+ . map ( |entity| DeferredEntity :: new ( entity, params. changes ) )
475+ else {
476+ // Client could predict despawn.
477+ debug ! ( "ignoring removals for despawned `{client_entity}`" ) ;
478+ message. advance ( data_size) ;
479+ return Ok ( ( ) ) ;
477480 } ;
478481
479482 params
@@ -482,8 +485,9 @@ fn apply_removals(
482485
483486 confirm_tick ( & mut client_entity, params. replicated , message_tick) ;
484487
485- let len = apply_array ( ArrayKind :: Sized , message, |message| {
486- let fns_id = postcard_utils:: from_buf ( message) ?;
488+ let mut data = message. split_to ( data_size) ;
489+ let len = apply_array ( ArrayKind :: Dynamic , & mut data, |data| {
490+ let fns_id = postcard_utils:: from_buf ( data) ?;
487491 let ( _, component_id, fns) = params. registry . get ( fns_id) ;
488492 let mut ctx = RemoveCtx {
489493 message_tick,
@@ -516,6 +520,7 @@ fn apply_changes(
516520 message_tick : RepliconTick ,
517521) -> Result < ( ) > {
518522 let server_entity = postcard_utils:: entity_from_buf ( message) ?;
523+ let data_size: usize = postcard_utils:: from_buf ( message) ?;
519524
520525 let world_cell = world. as_unsafe_world_cell ( ) ;
521526 let entities = world_cell. entities ( ) ;
@@ -525,7 +530,14 @@ fn apply_changes(
525530
526531 let mut client_entity = match params. entity_map . server_entry ( server_entity) {
527532 EntityEntry :: Occupied ( entry) => {
528- DeferredEntity :: new ( world. get_entity_mut ( entry. get ( ) ) ?, params. changes )
533+ let Ok ( client_entity) = world. get_entity_mut ( entry. get ( ) ) else {
534+ // Client could predict despawn.
535+ debug ! ( "ignoring changes for despawned `{}`" , entry. get( ) ) ;
536+ message. advance ( data_size) ;
537+ return Ok ( ( ) ) ;
538+ } ;
539+
540+ DeferredEntity :: new ( client_entity, params. changes )
529541 }
530542 EntityEntry :: Vacant ( entry) => {
531543 let mut client_entity = DeferredEntity :: new ( world. spawn_empty ( ) , params. changes ) ;
@@ -541,8 +553,9 @@ fn apply_changes(
541553
542554 confirm_tick ( & mut client_entity, params. replicated , message_tick) ;
543555
544- let len = apply_array ( ArrayKind :: Sized , message, |message| {
545- let fns_id = postcard_utils:: from_buf ( message) ?;
556+ let mut data = message. split_to ( data_size) ;
557+ let len = apply_array ( ArrayKind :: Dynamic , & mut data, |data| {
558+ let fns_id = postcard_utils:: from_buf ( data) ?;
546559 let ( _, component_id, fns) = params. registry . get ( fns_id) ;
547560 let mut ctx = WriteCtx {
548561 entity_map : params. entity_map ,
@@ -557,7 +570,7 @@ fn apply_changes(
557570 client_entity. id( ) ,
558571 ) ;
559572
560- fns. write ( & mut ctx, params. entity_markers , & mut client_entity, message ) ?;
573+ fns. write ( & mut ctx, params. entity_markers , & mut client_entity, data ) ?;
561574
562575 Ok ( ( ) )
563576 } ) ?;
@@ -645,8 +658,16 @@ fn apply_mutations(
645658 // The latter won't apply any structural changes until `flush`, and `Entities` won't be used afterward.
646659 let world = unsafe { world_cell. world_mut ( ) } ;
647660
648- let mut client_entity =
649- DeferredEntity :: new ( world. get_entity_mut ( client_entity) ?, params. changes ) ;
661+ let Ok ( mut client_entity) = world
662+ . get_entity_mut ( client_entity)
663+ . map ( |entity| DeferredEntity :: new ( entity, params. changes ) )
664+ else {
665+ // Client could predict despawn.
666+ debug ! ( "ignoring mutations for despawned `{client_entity}`" ) ;
667+ message. advance ( data_size) ;
668+ return Ok ( ( ) ) ;
669+ } ;
670+
650671 params
651672 . entity_markers
652673 . read ( params. command_markers , & * client_entity) ;
0 commit comments