1use std::ops::{Deref, DerefMut};
2use std::sync::{Arc, RwLock, Mutex};
3use std::time::{Instant, Duration};
4use std::error::Error;
5use std::fmt::{Debug, Formatter};
6
7use crossbeam_channel::{Sender, Receiver, unbounded, bounded};
8use hecs::EntityBuilder;
9use thiserror::Error;
10
11use super::chunk::{Chunk, ChunkHeight};
12use crate::world::chunk::ChunkStatus;
13use crate::world::level::LevelEnv;
14use crate::block::BlockState;
15
16
17#[derive(Error, Debug)]
19pub enum LevelSourceError {
20 #[error("The required chunk position is not supported by the source.")]
21 UnsupportedChunkPosition,
22 #[error("Chunk loading is not supported by the targeted source.")]
23 UnsupportedChunkLoad,
24 #[error("Chunk saving is not supported by the targeted source.")]
25 UnsupportedChunkSave,
26 #[error("Custom source error: {0}")]
27 Custom(Box<dyn Error + Send>)
28}
29
30impl LevelSourceError {
31 pub fn new_custom(err: impl Error + Send + 'static) -> Self {
32 Self::Custom(Box::new(err))
33 }
34}
35
36
37pub trait LevelSource {
41
42 fn request_chunk_load(&mut self, req: ChunkLoadRequest) -> Result<(), (LevelSourceError, ChunkLoadRequest)> {
47 Err((LevelSourceError::UnsupportedChunkLoad, req))
48 }
49
50 fn poll_chunk(&mut self) -> Option<Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)>> {
55 None
56 }
57
58 #[allow(unused_variables)]
60 fn request_chunk_save(&mut self, req: ChunkSaveRequest) -> Result<(), LevelSourceError> {
61 Err(LevelSourceError::UnsupportedChunkSave)
62 }
63
64}
65
66
67#[derive(Clone, Debug)]
70pub struct ChunkLoadRequest {
71 pub env: Arc<LevelEnv>,
72 pub height: ChunkHeight,
73 pub cx: i32,
74 pub cz: i32,
75}
76
77impl ChunkLoadRequest {
78
79 pub fn build_chunk(&self) -> Chunk {
81 Chunk::new(Arc::clone(&self.env), self.height, self.cx, self.cz)
82 }
83
84 pub fn build_proto_chunk(&self) -> ProtoChunk {
85 ProtoChunk {
86 inner: Box::new(self.build_chunk()),
87 proto_entities: Vec::new(),
88 dirty: false
89 }
90 }
91
92}
93
94#[derive(Clone)]
95pub struct ChunkSaveRequest {
96 pub cx: i32,
97 pub cz: i32,
98 pub chunk: Arc<RwLock<Chunk>>
99}
100
101
102pub struct ProtoChunk {
105 pub(super) inner: Box<Chunk>,
108 pub(super) proto_entities: Vec<(EntityBuilder, Vec<usize>)>,
110 pub dirty: bool
112}
113
114impl ProtoChunk {
115
116 pub fn add_proto_entity(&mut self, entity_builder: EntityBuilder) -> usize {
123 let idx = self.proto_entities.len();
124 self.proto_entities.push((entity_builder, Vec::new()));
125 idx
126 }
127
128 pub fn add_proto_entity_passengers(&mut self, host_index: usize, passenger_index: usize) {
129 self.proto_entities[host_index].1.push(passenger_index);
130 }
131
132}
133
134impl Deref for ProtoChunk {
135 type Target = Chunk;
136 fn deref(&self) -> &Self::Target {
137 &self.inner
138 }
139}
140
141impl DerefMut for ProtoChunk {
142 fn deref_mut(&mut self) -> &mut Self::Target {
143 &mut self.inner
144 }
145}
146
147impl Debug for ProtoChunk {
148 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("ProtoChunk")
150 .field("dirty", &self.dirty)
151 .field("proto_entities", &self.proto_entities.len())
152 .finish_non_exhaustive()
153 }
154}
155
156
157pub struct NullLevelSource;
159impl LevelSource for NullLevelSource {}
160
161
162pub struct LoadOrGenLevelSource<L, G> {
168 loader: L,
169 generator: G
170}
171
172impl<L, G> LoadOrGenLevelSource<L, G>
173where
174 L: LevelSource,
175 G: LevelSource,
176{
177
178 pub fn new(loader: L, generator: G) -> Self {
183 Self {
184 loader,
185 generator
186 }
187 }
188
189}
190
191impl<L, G> LevelSource for LoadOrGenLevelSource<L, G>
192where
193 L: LevelSource,
194 G: LevelSource,
195{
196
197 fn request_chunk_load(&mut self, req: ChunkLoadRequest) -> Result<(), (LevelSourceError, ChunkLoadRequest)> {
198 match self.loader.request_chunk_load(req) {
199 Err((LevelSourceError::UnsupportedChunkPosition, info)) => {
200 self.generator.request_chunk_load(info)
202 }
203 Err(e) => Err(e),
204 _ => Ok(())
205 }
206 }
207
208 fn poll_chunk(&mut self) -> Option<Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)>> {
209
210 while let Some(res) = self.loader.poll_chunk() {
212 match res {
213 Err((LevelSourceError::UnsupportedChunkPosition, chunk_info)) => {
215 match self.generator.request_chunk_load(chunk_info) {
216 Err(e) => return Some(Err(e)),
217 Ok(_) => {}
218 }
219 },
220 res => return Some(res)
222 }
223 }
224
225 let mut res = self.generator.poll_chunk();
227 if let Some(Ok(ref mut proto_chunk)) = res {
228 proto_chunk.dirty = true;
231 }
232 res
233
234 }
235
236 fn request_chunk_save(&mut self, req: ChunkSaveRequest) -> Result<(), LevelSourceError> {
237 self.loader.request_chunk_save(req)
238 }
239
240}
241
242
243pub trait LevelGenerator {
248 fn generate(&mut self, info: ChunkLoadRequest) -> Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)>;
249}
250
251
252pub trait LevelGeneratorBuilder {
256 type Generator: LevelGenerator;
257 fn build(&mut self) -> Self::Generator;
258}
259
260
261pub struct WorkerGenLevelSource {
265 request_sender: Sender<ChunkLoadRequest>,
266 result_receiver: Receiver<Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)>>,
267}
268
269impl WorkerGenLevelSource {
270
271 pub fn new<B>(generator_builder: B, workers_count: usize) -> Self
272 where
273 B: LevelGeneratorBuilder + Send + Sync + 'static
274 {
275
276 let (
277 request_sender,
278 request_receiver
279 ) = unbounded();
280
281 let (
282 result_sender,
283 result_receiver
284 ) = bounded(workers_count * 128);
285
286 let generator_builder = Arc::new(Mutex::new(generator_builder));
287
288 for i in 0..workers_count {
289
290 let request_receiver = request_receiver.clone();
291 let result_sender = result_sender.clone();
292 let generator_builder = Arc::clone(&generator_builder);
293
294 std::thread::Builder::new()
295 .name(format!("Level generator worker #{}", i))
296 .spawn(move || {
297 let worker = {
298 LevelGeneratorSourceWorker {
299 generator: generator_builder.lock().unwrap().build(),
300 request_receiver,
301 result_sender,
302 total_count: 0,
303 total_duration: Duration::default(),
304 }
305 };
306 worker.run()
307 })
308 .unwrap();
309
310 }
311
312 Self {
313 request_sender,
314 result_receiver
315 }
316
317 }
318
319}
320
321impl LevelSource for WorkerGenLevelSource {
322
323 fn request_chunk_load(&mut self, req: ChunkLoadRequest) -> Result<(), (LevelSourceError, ChunkLoadRequest)> {
324 self.request_sender.send(req).unwrap();
326 Ok(())
327 }
328
329 fn poll_chunk(&mut self) -> Option<Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)>> {
330 self.result_receiver.try_recv().ok()
331 }
332
333}
334
335struct LevelGeneratorSourceWorker<G> {
337 generator: G,
338 request_receiver: Receiver<ChunkLoadRequest>,
339 result_sender: Sender<Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)>>,
340 total_count: u32,
341 total_duration: Duration
342}
343
344impl<G> LevelGeneratorSourceWorker<G>
345where
346 G: LevelGenerator
347{
348
349 fn run(mut self) {
350 loop {
351 match self.request_receiver.recv() {
353 Ok(chunk_info) => {
354 let begin = Instant::now();
355 let res = self.generator.generate(chunk_info);
356 self.total_duration += begin.elapsed();
357 self.total_count += 1;
358 if let Err(_) = self.result_sender.send(res) {
360 break
361 }
362 },
363 Err(_) => break
364 }
365 }
366 }
367
368}
369
370
371#[derive(Debug, Clone)]
374pub struct SuperFlatGenerator {
375 layers: Vec<(&'static BlockState, i32, u32)>
376}
377
378impl SuperFlatGenerator {
379
380 pub fn new() -> Self {
381 Self {
382 layers: Vec::new()
383 }
384 }
385
386 pub fn add_layer(&mut self, state: &'static BlockState, y: i32, height: u32) {
387 self.layers.push((state, y, height));
388 }
389
390}
391
392impl LevelGenerator for SuperFlatGenerator {
393
394 fn generate(&mut self, info: ChunkLoadRequest) -> Result<ProtoChunk, (LevelSourceError, ChunkLoadRequest)> {
395 let mut chunk = info.build_proto_chunk();
396 for &(state, y, height) in &self.layers {
397 for y in y..(y + height as i32) {
398 for x in 0..16 {
401 for z in 0..16 {
402 let _ = chunk.set_block(x, y, z, state);
403 }
404 }
405 }
406 }
407 chunk.set_status(ChunkStatus::Full);
408 Ok(chunk)
409 }
410
411}