summary refs log tree commit diff
path: root/src/World/Generation/ChunkNeighbors.cpp
blob: c3ae5cbd2687520a6d2c10f52ecb019b17adda5e (plain)
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
#include "ChunkNeighbors.hpp"

namespace MC::World::Generation {

ChunkNeighbors find_chunk_neighbors(ChunkIndex chunk, ChunkRegistry& chunks) {
    UInt neighbor_index = 0;
    std::array<Chunk*, 8> neighbors{};
    for (I32 x = -1; x <= 1; x++) {
        for (I32 y = -1; y <= 1; y++) {
            if (x == 0 && y == 0) continue;

            auto& neighbor_data = chunks.get({chunk.x + x, chunk.y + y});
            if (neighbor_data.chunk.has_value()) neighbors[neighbor_index++] = &neighbor_data.chunk.value();
        }
    }

    // Layout of neighboring chunks in `neighbors` array:
    // (-1; -1) > (-1;  0) > (-1; 1) > (0; -1)
    // ( 0;  1) > ( 1; -1) > ( 1; 0) > (1;  1)
    return {
        neighbors[3], neighbors[6], neighbors[4], neighbors[1],
        neighbors[5], neighbors[7], neighbors[2], neighbors[0],
    };
}

GetBlockWrappingResult get_block_wrapping(const Chunk& chunk, const ChunkNeighbors& neighbors, Vector<3, I32> pos) {
    const Chunk* chunk_to_ask;

    auto overflow = [](I32& c, I32 max) -> I8 {
        if (c < 0) { c += max; return -1; }
        if (c >= max) { c -= max; return 1; }
        return 0;
    };

    auto xo = overflow(pos.x(), Chunk::Width);
    auto yo = overflow(pos.y(), Chunk::Height);
    auto zo = overflow(pos.z(), Chunk::Width);

    // Blocks above and below a chunk are always Air.
    if (yo != 0) return {};

    if (xo == 1 && zo == 1) { chunk_to_ask = neighbors.south_east; }
    else if (xo == 1 && zo == -1) { chunk_to_ask = neighbors.north_east; }
    else if (xo == -1 && zo == 1) { chunk_to_ask = neighbors.south_west; }
    else if (xo == -1 && zo == -1) { chunk_to_ask = neighbors.north_west; }
    else if (xo == 1) { chunk_to_ask = neighbors.east; }
    else if (xo == -1) { chunk_to_ask = neighbors.west; }
    else if (zo == 1) { chunk_to_ask = neighbors.south; }
    else if (zo == -1) { chunk_to_ask = neighbors.north; }
    else { chunk_to_ask = &chunk; }

    if (!chunk_to_ask) return {false};
    return {true, chunk_to_ask->at(pos.x(), pos.y(), pos.z())};
}

}