1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use linked_hash_set::LinkedHashSet;
use rayon::slice::ParallelSliceMut;
use specs::{Component, VecStorage};

use crate::Vec2;

/// A list of chunks that the entity is requesting to generate.
#[derive(Default, Component)]
#[storage(VecStorage)]
pub struct ChunkRequestsComp {
    pub pending: LinkedHashSet<Vec2<i32>>,
    pub loaded: LinkedHashSet<Vec2<i32>>,
}

impl ChunkRequestsComp {
    /// Create a component of a new list of chunk requests.
    pub fn new() -> Self {
        Self::default()
    }

    /// Add a requested chunk.
    pub fn add(&mut self, coords: &Vec2<i32>) {
        self.pending.insert(coords.to_owned());
    }

    /// Finish a requested chunk, add it to `loaded`.
    pub fn mark_finish(&mut self, coords: &Vec2<i32>) {
        self.pending.remove(coords);
        self.loaded.insert(coords.to_owned());
    }

    /// Unload a chunk, remove from both requests and loaded
    pub fn unload(&mut self, coords: &Vec2<i32>) {
        self.pending.remove(coords);
        self.loaded.remove(coords);
    }

    /// Sort pending chunks.
    pub fn sort_pending(&mut self, center: &Vec2<i32>) {
        let Vec2(cx, cz) = center;

        let mut pendings: Vec<Vec2<i32>> = self.pending.clone().into_iter().collect();

        pendings.par_sort_by(|c1, c2| {
            let dist1 = (c1.0 - cx).pow(2) + (c1.1 - cz).pow(2);
            let dist2 = (c2.0 - cx).pow(2) + (c2.1 - cz).pow(2);
            dist1.cmp(&dist2)
        });

        let list = LinkedHashSet::from_iter(pendings.into_iter());

        self.pending = list;
    }

    /// Check to see if this chunk request is interested in a chunk.
    pub fn is_interested(&self, coords: &Vec2<i32>) -> bool {
        self.loaded.contains(coords)
    }

    /// Check to see if this client has requested or loaded a chunk.
    pub fn has(&self, coords: &Vec2<i32>) -> bool {
        self.pending.contains(coords) || self.loaded.contains(coords)
    }
}