summaryrefslogtreecommitdiffstats
path: root/src/Section.cpp
blob: 1d9c2032921e385c71189323b9c1015215a981b1 (plain) (blame)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "Section.hpp"

#include <bitset>
#include <cstring>

void Section::CalculateHash() const {
    if (block.empty()) {
        hash = 0;
        return;
    }


    size_t offset = 0;

    std::vector<unsigned char> rawData;    
    rawData.resize(block.size() * sizeof(long long) + 4096);
    
	std::memcpy(rawData.data(), light, 2048);
	std::memcpy(rawData.data() + 2048, sky, 2048);
	std::memcpy(rawData.data() + 4096, block.data(), block.size() * sizeof(long long));    
	
    for (auto& it : overrideList) {
        rawData.push_back(*reinterpret_cast<const unsigned short*> (&it.second) & 0xF);
        rawData.push_back(*reinterpret_cast<const unsigned short*> (&it.second) >> 0xF);
    }
    
    const unsigned char *from = reinterpret_cast<const unsigned char *>(rawData.data());
    size_t length = rawData.size();

    std::string str(from, from + length);
    hash =  std::hash<std::string>{}(str);
}

Section::Section(Vector pos, unsigned char bitsPerBlock, std::vector<unsigned short> palette, std::vector<long long> blockData, const std::vector<unsigned char> &lightData, const std::vector<unsigned char> &skyData) {
    if (bitsPerBlock < 4)
        bitsPerBlock = 4;
    if (bitsPerBlock > 8)
        bitsPerBlock = 13;
    this->bitsPerBlock = bitsPerBlock;

    this->worldPosition = pos;
    this->block = std::move(blockData);
    this->palette = std::move(palette);
	std::copy(lightData.begin(), lightData.end(), light);
    if (!skyData.empty())
        std::copy(skyData.begin(), skyData.end(), sky);
    else
        memset(sky, 0, sizeof(sky));

    hash = -1;
	CalculateHash();
}

BlockId Section::GetBlockId(Vector pos) const {
    if (block.empty())
        return BlockId{ 0,0 };

    if (!overrideList.empty()) {
        auto iter = overrideList.find(pos);
        if (iter != overrideList.end())
            return iter->second;
    }

    unsigned int value;

    unsigned int individualValueMask = ((1 << (unsigned int)bitsPerBlock) - 1);

    int blockNumber = (((pos.y * 16) + pos.z) * 16) + pos.x;
    int startLong = (blockNumber * bitsPerBlock) / 64;
    int startOffset = (blockNumber * bitsPerBlock) % 64;
    int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64;

    unsigned int t;

    if (startLong == endLong) {
        t = (block[startLong] >> startOffset);
    }
    else {
        int endOffset = 64 - startOffset;
        t = (block[startLong] >> startOffset |block[endLong] << endOffset);
    }

    t &= individualValueMask;


    if (t >= palette.size()) {
        //LOG(ERROR) << "Out of palette: " << t;
        value = t;
    }
    else
        value = palette[t];

    BlockId blockId;
    blockId.id = value >> 4;
    blockId.state = value & 0xF;
    return blockId;
}

unsigned char Section::GetBlockLight(Vector pos) const
{
	int blockNumber = pos.y * 256 + pos.z * 16 + pos.x;
	unsigned char lightValue = this->light[blockNumber / 2];
	return (blockNumber % 2 == 0) ? (lightValue & 0xF) : (lightValue >> 4);
}

unsigned char Section::GetBlockSkyLight(Vector pos) const
{
	int blockNumber = pos.y * 256 + pos.z * 16 + pos.x;
    unsigned char skyValue = this->sky[blockNumber / 2];
    return (blockNumber % 2 == 0) ? (skyValue & 0xF) : (skyValue >> 4);
}

void Section::SetBlockId(Vector pos, BlockId value) {
    overrideList[pos] = value;
    hash = -1;
	CalculateHash();
}

Vector Section::GetPosition() const {
	return worldPosition;
}

size_t Section::GetHash() const {
    if (hash == -1)
        CalculateHash();
    return hash;
}