GeezerVison is showing github.com — Skip sending chunks which failed to load - see #71 · feather-rs/feather@1da7838
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: server/src/chunk_logic.rs +15-4Lines changed: 15 additions & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -39,18 +39,25 @@ pub struct ChunkLoadEvent { | 39 | 39 | pub pos: ChunkPosition, | 40 | 40 | } | 41 | 41 |
| | 42 | +/// Event which is triggered when a chunk fails to load. | | 43 | +#[derive(Debug, Clone, Copy)] | | 44 | +pub struct ChunkLoadFailEvent { | | 45 | + pub pos: ChunkPosition, | | 46 | +} | | 47 | + | 42 | 48 | /// System for receiving loaded chunks from the chunk worker thread. | 43 | 49 | pub struct ChunkLoadSystem; | 44 | 50 |
| 45 | 51 | impl<'a> System<'a> for ChunkLoadSystem { | 46 | 52 | type SystemData = ( | 47 | 53 | Write<'a, ChunkMap>, | 48 | 54 | Write<'a, EventChannel<ChunkLoadEvent>>, | | 55 | + Write<'a, EventChannel<ChunkLoadFailEvent>>, | 49 | 56 | Read<'a, ChunkWorkerHandle>, | 50 | 57 | ); | 51 | 58 |
| 52 | 59 | fn run(&mut self, data: Self::SystemData) { | 53 | | - let (mut chunk_map, mut events, handle) = data; | | 60 | + let (mut chunk_map, mut load_events, mut fail_events, handle) = data; | 54 | 61 |
| 55 | 62 | while let Ok((pos, result)) = handle.receiver.try_recv() { | 56 | 63 | match result { | @@ -59,13 +66,15 @@ impl<'a> System<'a> for ChunkLoadSystem { | 59 | 66 |
| 60 | 67 | // Trigger event | 61 | 68 | let event = ChunkLoadEvent { pos }; | 62 | | - events.single_write(event); | | 69 | + load_events.single_write(event); | 63 | 70 |
| 64 | 71 | trace!("Loaded chunk at {:?}", pos); | 65 | 72 | } | 66 | 73 | Err(err) => { | 67 | 74 | // TODO generate chunk if it didn't exist | 68 | 75 | warn!("Failed to load chunk at {:?}: {}", pos, err); | | 76 | + let event = ChunkLoadFailEvent { pos }; | | 77 | + fail_events.single_write(event); | 69 | 78 | } | 70 | 79 | } | 71 | 80 | } | @@ -431,13 +440,15 @@ mod tests { | 431 | 440 | let pos = ChunkPosition::new(0, 0); | 432 | 441 | send2.send((pos, Ok(Chunk::new(pos)))).unwrap(); | 433 | 442 |
| 434 | | - let event_channel = EventChannel::<ChunkLoadEvent>::new(); | | 443 | + let load_event_channel = EventChannel::<ChunkLoadEvent>::new(); | | 444 | + let fail_event_channel = EventChannel::<ChunkLoadFailEvent>::new(); | 435 | 445 |
| 436 | 446 | let mut system = ChunkLoadSystem; | 437 | 447 | let mut world = World::new(); | 438 | 448 | world.insert(chunk_map); | 439 | 449 | world.insert(handle); | 440 | | - world.insert(event_channel); | | 450 | + world.insert(load_event_channel); | | 451 | + world.insert(fail_event_channel); | 441 | 452 |
| 442 | 453 | system.run_now(&world); | 443 | 454 |
| |
Collapse file Copy file name to clipboardExpand all lines: server/src/entity/chunk.rs +9-3Lines changed: 9 additions & 3 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -43,9 +43,15 @@ impl ChunkEntities { | 43 | 43 | /// May panic in some cases if the entity is not contained | 44 | 44 | /// within the given chunk. | 45 | 45 | pub fn remove_from_chunk(&mut self, chunk: ChunkPosition, entity: Entity) { | 46 | | - let vec = self.0.get_mut(&chunk).unwrap(); | 47 | | - | 48 | | - let (index, _) = vec.iter().enumerate().find(|x| *x.1 == entity).unwrap(); | | 46 | + let vec = match self.0.get_mut(&chunk) { | | 47 | + Some(vec) => vec, | | 48 | + _ => return, | | 49 | + }; | | 50 | + | | 51 | + let (index, _) = match vec.iter().enumerate().find(|x| *x.1 == entity) { | | 52 | + Some(index) => index, | | 53 | + None => return, | | 54 | + }; | 49 | 55 | vec.swap_remove(index); | 50 | 56 |
| 51 | 57 | if vec.is_empty() { | |
Collapse file Copy file name to clipboardExpand all lines: server/src/player/movement.rs +16-12Lines changed: 16 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -8,9 +8,8 @@ use shrev::{EventChannel, ReaderId}; | 8 | 8 | use specs::storage::{BTreeStorage, ComponentEvent}; | 9 | 9 | use specs::{ | 10 | 10 | BitSet, Component, Entities, Entity, Join, LazyUpdate, ParJoin, Read, ReadStorage, System, | 11 | | - World, Write, WriteStorage, | | 11 | + WorldExt, Write, WriteStorage, | 12 | 12 | }; | 13 | | -use specs::{SystemData, WorldExt}; | 14 | 13 |
| 15 | 14 | use feather_core::network::cast_packet; | 16 | 15 | use feather_core::network::packet::implementation::{ | @@ -22,7 +21,7 @@ use feather_core::world::{ChunkMap, ChunkPosition, Position}; | 22 | 21 |
| 23 | 22 | use crate::chunk_logic::{ | 24 | 23 | load_chunk, ChunkHolderComponent, ChunkHolderReleaseEvent, ChunkHolders, ChunkLoadEvent, | 25 | | - ChunkWorkerHandle, | | 24 | + ChunkLoadFailEvent, ChunkWorkerHandle, | 26 | 25 | }; | 27 | 26 | use crate::config::Config; | 28 | 27 | use crate::entity::PositionComponent; | @@ -278,6 +277,7 @@ impl<'a> System<'a> for ChunkCrossSystem { | 278 | 277 | #[derive(Default)] | 279 | 278 | pub struct ChunkSendSystem { | 280 | 279 | load_event_reader: Option<ReaderId<ChunkLoadEvent>>, | | 280 | + fail_event_reader: Option<ReaderId<ChunkLoadFailEvent>>, | 281 | 281 | } | 282 | 282 |
| 283 | 283 | impl<'a> System<'a> for ChunkSendSystem { | @@ -286,10 +286,11 @@ impl<'a> System<'a> for ChunkSendSystem { | 286 | 286 | ReadStorage<'a, NetworkComponent>, | 287 | 287 | Read<'a, ChunkMap>, | 288 | 288 | Read<'a, EventChannel<ChunkLoadEvent>>, | | 289 | + Read<'a, EventChannel<ChunkLoadFailEvent>>, | 289 | 290 | ); | 290 | 291 |
| 291 | 292 | fn run(&mut self, data: Self::SystemData) { | 292 | | - let (mut pendings, netcomps, chunk_map, load_events) = data; | | 293 | + let (mut pendings, netcomps, chunk_map, load_events, fail_events) = data; | 293 | 294 |
| 294 | 295 | for event in load_events.read(&mut self.load_event_reader.as_mut().unwrap()) { | 295 | 296 | // TODO perhaps this is slightly inefficient? | @@ -306,16 +307,19 @@ impl<'a> System<'a> for ChunkSendSystem { | 306 | 307 | } | 307 | 308 | }); | 308 | 309 | } | 309 | | - } | 310 | 310 |
| 311 | | - fn setup(&mut self, world: &mut World) { | 312 | | - Self::SystemData::setup(world); | 313 | | - self.load_event_reader = Some( | 314 | | - world | 315 | | - .fetch_mut::<EventChannel<ChunkLoadEvent>>() | 316 | | - .register_reader(), | 317 | | - ); | | 311 | + for event in fail_events.read(self.fail_event_reader.as_mut().unwrap()) { | | 312 | + (&mut pendings).par_join().for_each(|pending| { | | 313 | + if pending.contains(&event.pos) { | | 314 | + // The chunk failed to load - skip sending it. | | 315 | + // See issue #71 | | 316 | + pending.remove(&event.pos); | | 317 | + } | | 318 | + }); | | 319 | + } | 318 | 320 | } | | 321 | + | | 322 | + setup_impl!(load_event_reader, fail_event_reader); | 319 | 323 | } | 320 | 324 |
| 321 | 325 | /// System for sending the Unload Chunk packet when the time comes. | |
|