You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

95 lines
2.9 KiB

  1. use crate::metrics::ChunkGenMetrics;
  2. #[cfg(not(feature = "worldgen"))]
  3. use crate::test_world::{IndexOwned, World};
  4. use common::{generation::ChunkSupplement, terrain::TerrainChunk};
  5. use crossbeam::channel;
  6. use hashbrown::{hash_map::Entry, HashMap};
  7. use specs::Entity as EcsEntity;
  8. use std::sync::{
  9. atomic::{AtomicBool, Ordering},
  10. Arc,
  11. };
  12. use vek::*;
  13. #[cfg(feature = "worldgen")]
  14. use world::{IndexOwned, World};
  15. type ChunkGenResult = (
  16. Vec2<i32>,
  17. Result<(TerrainChunk, ChunkSupplement), Option<EcsEntity>>,
  18. );
  19. pub struct ChunkGenerator {
  20. chunk_tx: channel::Sender<ChunkGenResult>,
  21. chunk_rx: channel::Receiver<ChunkGenResult>,
  22. pending_chunks: HashMap<Vec2<i32>, Arc<AtomicBool>>,
  23. metrics: Arc<ChunkGenMetrics>,
  24. }
  25. impl ChunkGenerator {
  26. #[allow(clippy::new_without_default)] // TODO: Pending review in #587
  27. pub fn new(metrics: ChunkGenMetrics) -> Self {
  28. let (chunk_tx, chunk_rx) = channel::unbounded();
  29. Self {
  30. chunk_tx,
  31. chunk_rx,
  32. pending_chunks: HashMap::new(),
  33. metrics: Arc::new(metrics),
  34. }
  35. }
  36. pub fn generate_chunk(
  37. &mut self,
  38. entity: Option<EcsEntity>,
  39. key: Vec2<i32>,
  40. thread_pool: &mut uvth::ThreadPool,
  41. world: Arc<World>,
  42. index: IndexOwned,
  43. ) {
  44. let v = if let Entry::Vacant(v) = self.pending_chunks.entry(key) {
  45. v
  46. } else {
  47. return;
  48. };
  49. let cancel = Arc::new(AtomicBool::new(false));
  50. v.insert(Arc::clone(&cancel));
  51. let chunk_tx = self.chunk_tx.clone();
  52. self.metrics.chunks_requested.inc();
  53. thread_pool.execute(move || {
  54. let index = index.as_index_ref();
  55. let payload = world
  56. .generate_chunk(index, key, || cancel.load(Ordering::Relaxed))
  57. .map_err(|_| entity);
  58. let _ = chunk_tx.send((key, payload));
  59. });
  60. }
  61. pub fn recv_new_chunk(&mut self) -> Option<ChunkGenResult> {
  62. if let Ok((key, res)) = self.chunk_rx.try_recv() {
  63. self.pending_chunks.remove(&key);
  64. self.metrics.chunks_served.inc();
  65. // TODO: do anything else if res is an Err?
  66. Some((key, res))
  67. } else {
  68. None
  69. }
  70. }
  71. pub fn pending_chunks<'a>(&'a self) -> impl Iterator<Item = Vec2<i32>> + 'a {
  72. self.pending_chunks.keys().copied()
  73. }
  74. pub fn cancel_if_pending(&mut self, key: Vec2<i32>) {
  75. if let Some(cancel) = self.pending_chunks.remove(&key) {
  76. cancel.store(true, Ordering::Relaxed);
  77. self.metrics.chunks_canceled.inc();
  78. }
  79. }
  80. pub fn cancel_all(&mut self) {
  81. let metrics = self.metrics.clone();
  82. self.pending_chunks.drain().for_each(|(_, cancel)| {
  83. cancel.store(true, Ordering::Relaxed);
  84. metrics.chunks_canceled.inc();
  85. });
  86. }
  87. }