Skip to content

Commit e4440a7

Browse files
committed
Creates files for version compatibility functions
1 parent fe55715 commit e4440a7

File tree

9 files changed

+306
-229
lines changed

9 files changed

+306
-229
lines changed

src/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ SET(SOURCES ${SOURCES}
2121
section.cpp
2222
settings.cpp
2323
worldloader.cpp
24+
chunk_format_versions/assert.cpp
25+
chunk_format_versions/get_section.cpp
26+
chunk_format_versions/section_format.cpp
2427
VERSION)
2528

2629
ADD_LIBRARY(mcmap_core STATIC ${SOURCES})

src/chunk.cpp

Lines changed: 4 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,23 @@
11
#include "./chunk.h"
2+
#include "./chunk_format_versions/assert.hpp"
3+
#include "./chunk_format_versions/get_section.hpp"
24
#include <compat.hpp>
35
#include <functional>
46

57
namespace mcmap {
68

79
namespace versions {
8-
namespace assert_versions {
9-
#ifdef SNAPSHOT_SUPPORT
10-
bool v2844(const nbt::NBT &chunk) {
11-
// Snapshot 21w43a
12-
return chunk.contains("sections") // No sections mean no blocks
13-
&& chunk.contains("Status") // Ensure the status is `full`
14-
&& chunk["Status"].get<nbt::NBT::tag_string_t>() == "full";
15-
}
16-
17-
bool v2840(const nbt::NBT &chunk) {
18-
// Snapshot 21w42a
19-
return chunk.contains("Level") && // Level data is required
20-
chunk["Level"].contains("Sections") // No sections mean no blocks
21-
&& chunk["Level"].contains("Status") // Ensure the status is `full`
22-
&& chunk["Level"]["Status"].get<nbt::NBT::tag_string_t>() == "full";
23-
}
24-
#endif
25-
26-
bool v1976(const nbt::NBT &chunk) {
27-
// From 1.14 onwards
28-
return chunk.contains("Level") // Level data is required
29-
&& chunk["Level"].contains("Sections") // No sections mean no blocks
30-
&& chunk["Level"].contains("Status") // Ensure the status is `full`
31-
&& chunk["Level"]["Status"].get<nbt::NBT::tag_string_t>() == "full";
32-
}
33-
34-
bool v1628(const nbt::NBT &chunk) {
35-
// From 1.13 onwards
36-
return chunk.contains("Level") // Level data is required
37-
&& chunk["Level"].contains("Sections") // No sections mean no blocks
38-
&& chunk["Level"].contains("Status") // Ensure the status is `full`
39-
&& chunk["Level"]["Status"].get<nbt::NBT::tag_string_t>() ==
40-
"postprocessed";
41-
}
42-
43-
bool catchall(const nbt::NBT &chunk) {
44-
logger::deep_debug("Unsupported DataVersion: {}\n",
45-
chunk["DataVersion"].get<int>());
46-
return false;
47-
}
48-
} // namespace assert_versions
49-
50-
namespace sections_versions {
51-
nbt::NBT v2844(const nbt::NBT &chunk) { return chunk["sections"]; }
52-
nbt::NBT v1628(const nbt::NBT &chunk) { return chunk["Level"]["Sections"]; }
53-
nbt::NBT catchall(const nbt::NBT &chunk) {
54-
logger::deep_debug("Unsupported DataVersion: {}\n",
55-
chunk["DataVersion"].get<int>());
56-
return nbt::NBT(std::vector<nbt::NBT>());
57-
}
58-
} // namespace sections_versions
59-
6010
std::map<int, std::function<bool(const nbt::NBT &)>> assert = {
11+
{2844, assert_versions::v2844},
6112
#ifdef SNAPSHOT_SUPPORT
62-
{2844, assert_versions::v2844}, {2840, assert_versions::v2840},
13+
{2840, assert_versions::v2840},
6314
#endif
6415
{1976, assert_versions::v1976}, {1628, assert_versions::v1628},
6516
{0, assert_versions::catchall},
6617
};
6718

6819
std::map<int, std::function<nbt::NBT(const nbt::NBT &)>> sections = {
69-
#ifdef SNAPSHOT_SUPPORT
7020
{2844, sections_versions::v2844},
71-
#endif
7221
{1628, sections_versions::v1628},
7322
{0, sections_versions::catchall},
7423
};

src/chunk_format_versions/assert.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#include "./assert.hpp"
2+
3+
namespace mcmap {
4+
namespace versions {
5+
namespace assert_versions {
6+
bool v2844(const nbt::NBT &chunk) {
7+
// Snapshot 21w43a
8+
return chunk.contains("sections") // No sections mean no blocks
9+
&& chunk.contains("Status") // Ensure the status is `full`
10+
&& chunk["Status"].get<nbt::NBT::tag_string_t>() == "full";
11+
}
12+
13+
#ifdef SNAPSHOT_SUPPORT
14+
bool v2840(const nbt::NBT &chunk) {
15+
// Snapshot 21w42a
16+
return chunk.contains("Level") && // Level data is required
17+
chunk["Level"].contains("Sections") // No sections mean no blocks
18+
&& chunk["Level"].contains("Status") // Ensure the status is `full`
19+
&& chunk["Level"]["Status"].get<nbt::NBT::tag_string_t>() == "full";
20+
}
21+
#endif
22+
23+
bool v1976(const nbt::NBT &chunk) {
24+
// From 1.14 onwards
25+
return chunk.contains("Level") // Level data is required
26+
&& chunk["Level"].contains("Sections") // No sections mean no blocks
27+
&& chunk["Level"].contains("Status") // Ensure the status is `full`
28+
&& chunk["Level"]["Status"].get<nbt::NBT::tag_string_t>() == "full";
29+
}
30+
31+
bool v1628(const nbt::NBT &chunk) {
32+
// From 1.13 onwards
33+
return chunk.contains("Level") // Level data is required
34+
&& chunk["Level"].contains("Sections") // No sections mean no blocks
35+
&& chunk["Level"].contains("Status") // Ensure the status is `full`
36+
&& chunk["Level"]["Status"].get<nbt::NBT::tag_string_t>() ==
37+
"postprocessed";
38+
}
39+
40+
bool catchall(const nbt::NBT &chunk) {
41+
logger::deep_debug("Unsupported DataVersion: {}\n",
42+
chunk["DataVersion"].get<int>());
43+
return false;
44+
}
45+
} // namespace assert_versions
46+
} // namespace versions
47+
} // namespace mcmap

src/chunk_format_versions/assert.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <nbt/nbt.hpp>
2+
3+
namespace mcmap {
4+
namespace versions {
5+
namespace assert_versions {
6+
bool v2844(const nbt::NBT &chunk);
7+
8+
#ifdef SNAPSHOT_SUPPORT
9+
bool v2840(const nbt::NBT &chunk);
10+
#endif
11+
12+
bool v1976(const nbt::NBT &chunk);
13+
14+
bool v1628(const nbt::NBT &chunk);
15+
16+
bool catchall(const nbt::NBT &chunk);
17+
} // namespace assert_versions
18+
} // namespace versions
19+
} // namespace mcmap
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "get_section.hpp"
2+
3+
namespace mcmap {
4+
namespace versions {
5+
namespace sections_versions {
6+
nbt::NBT v2844(const nbt::NBT &chunk) { return chunk["sections"]; }
7+
nbt::NBT v1628(const nbt::NBT &chunk) { return chunk["Level"]["Sections"]; }
8+
nbt::NBT catchall(const nbt::NBT &chunk) {
9+
logger::deep_debug("Unsupported DataVersion: {}\n",
10+
chunk["DataVersion"].get<int>());
11+
return nbt::NBT(std::vector<nbt::NBT>());
12+
}
13+
} // namespace sections_versions
14+
} // namespace versions
15+
} // namespace mcmap
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <nbt/nbt.hpp>
2+
3+
namespace mcmap {
4+
namespace versions {
5+
namespace sections_versions {
6+
nbt::NBT v2844(const nbt::NBT &);
7+
nbt::NBT v1628(const nbt::NBT &);
8+
nbt::NBT catchall(const nbt::NBT &);
9+
} // namespace sections_versions
10+
} // namespace versions
11+
} // namespace mcmap
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
#include "section_format.hpp"
2+
3+
namespace mcmap {
4+
namespace versions {
5+
namespace block_states_versions {
6+
void post116(const uint8_t index_length,
7+
const std::vector<int64_t> *blockStates,
8+
Section::block_array &buffer) {
9+
// NEW in 1.16, longs are padded by 0s when a block cannot fit, so no more
10+
// overflow to deal with !
11+
12+
for (uint16_t index = 0; index < 4096; index++) {
13+
// Determine how many indexes each long holds
14+
const uint8_t blocksPerLong = 64 / index_length;
15+
16+
// Calculate where in the long array is the long containing the right index.
17+
const uint16_t longIndex = index / blocksPerLong;
18+
19+
// Once we located a long, we have to know where in the 64 bits
20+
// the relevant block is located.
21+
const uint8_t padding = (index - longIndex * blocksPerLong) * index_length;
22+
23+
// Bring the data to the first bits of the long, then extract it by bitwise
24+
// comparison
25+
const uint16_t blockIndex = ((*blockStates)[longIndex] >> padding) &
26+
((uint64_t(1) << index_length) - 1);
27+
28+
buffer[index] = blockIndex;
29+
}
30+
}
31+
32+
void pre116(const uint8_t index_length, const std::vector<int64_t> *blockStates,
33+
Section::block_array &buffer) {
34+
// The `BlockStates` array contains data on the section's blocks. You have to
35+
// extract it by understanfing its structure.
36+
//
37+
// Although it is a array of long values, one must see it as an array of block
38+
// indexes, whose element size depends on the size of the Palette. This
39+
// routine locates the necessary long, extracts the block with bit
40+
// comparisons.
41+
//
42+
// The length of a block index has to be coded on the minimal possible size,
43+
// which is the logarithm in base2 of the size of the palette, or 4 if the
44+
// logarithm is smaller.
45+
46+
for (uint16_t index = 0; index < 4096; index++) {
47+
48+
// We skip the `position` first blocks, of length `size`, then divide by 64
49+
// to get the number of longs to skip from the array
50+
const uint16_t skip_longs = (index * index_length) >> 6;
51+
52+
// Once we located the data in a long, we have to know where in the 64 bits
53+
// it is located. This is the remaining of the previous operation
54+
const int8_t padding = (index * index_length) & 63;
55+
56+
// Sometimes the data of an index does not fit entirely into a long, so we
57+
// check if there is overflow
58+
const int8_t overflow =
59+
(padding + index_length > 64 ? padding + index_length - 64 : 0);
60+
61+
// This complicated expression extracts the necessary bits from the current
62+
// long.
63+
//
64+
// Lets say we need the following bits in a long (not to scale):
65+
// 10011100111001110011100
66+
// ^^^^^
67+
// We do this by shifting (>>) the data by padding, to get the relevant bits
68+
// on the end of the long:
69+
// ???????????????10011100
70+
// ^^^^^
71+
// We then apply a mask to get only the relevant bits:
72+
// ???????????????10011100
73+
// 00000000000000000011111 &
74+
// 00000000000000000011100 <- result
75+
//
76+
// The mask is made at the size of the data, using the formula (1 << n) - 1,
77+
// the resulting bitset is of the following shape: 0...01...1 with n 1s.
78+
//
79+
// If there is an overflow, the mask size is reduced, as not to catch noise
80+
// from the padding (ie the interrogation points earlier) that appear on
81+
// ARM32.
82+
uint16_t lower_data = ((*blockStates)[skip_longs] >> padding) &
83+
((uint64_t(1) << (index_length - overflow)) - 1);
84+
85+
if (overflow > 0) {
86+
// The exact same process is used to catch the overflow from the next long
87+
const uint16_t upper_data =
88+
((*blockStates)[skip_longs + 1]) & ((uint64_t(1) << overflow) - 1);
89+
// We then associate both values to create the final value
90+
lower_data = lower_data | (upper_data << (index_length - overflow));
91+
}
92+
93+
// lower_data now contains the index in the palette
94+
buffer[index] = lower_data;
95+
}
96+
}
97+
} // namespace block_states_versions
98+
99+
namespace init_versions {
100+
void v1628(Section *target, const nbt::NBT &raw_section) {
101+
if (raw_section.contains("BlockStates") && raw_section.contains("Palette")) {
102+
target->palette =
103+
*raw_section["Palette"].get<const std::vector<nbt::NBT> *>();
104+
const nbt::NBT::tag_long_array_t *blockStates =
105+
raw_section["BlockStates"].get<const nbt::NBT::tag_long_array_t *>();
106+
107+
// Remove the air that is default-constructed
108+
target->colors.clear();
109+
// Anticipate the color input from the palette's size
110+
target->colors.reserve(target->palette.size());
111+
112+
// The length in bits of a block is the log2 of the palette's size or 4,
113+
// whichever is greatest. Ranges from 4 to 12.
114+
const uint8_t blockBitLength =
115+
std::max(uint8_t(ceil(log2(target->palette.size()))), uint8_t(4));
116+
117+
// Parse the blockstates for block info
118+
block_states_versions::pre116(blockBitLength, blockStates, target->blocks);
119+
}
120+
}
121+
122+
void v2534(Section *target, const nbt::NBT &raw_section) {
123+
if (raw_section.contains("BlockStates") && raw_section.contains("Palette")) {
124+
target->palette =
125+
*raw_section["Palette"].get<const std::vector<nbt::NBT> *>();
126+
const nbt::NBT::tag_long_array_t *blockStates =
127+
raw_section["BlockStates"].get<const nbt::NBT::tag_long_array_t *>();
128+
129+
// Remove the air that is default-constructed
130+
target->colors.clear();
131+
// Anticipate the color input from the palette's size
132+
target->colors.reserve(target->palette.size());
133+
134+
// The length in bits of a block is the log2 of the palette's size or 4,
135+
// whichever is greatest. Ranges from 4 to 12.
136+
const uint8_t blockBitLength =
137+
std::max(uint8_t(ceil(log2(target->palette.size()))), uint8_t(4));
138+
139+
// Parse the blockstates for block info
140+
block_states_versions::post116(blockBitLength, blockStates, target->blocks);
141+
}
142+
}
143+
144+
#ifdef SNAPSHOT_SUPPORT
145+
void v2840(Section *target, const nbt::NBT &raw_section) {
146+
if (raw_section.contains("block_states") &&
147+
raw_section["block_states"].contains("data") &&
148+
raw_section["block_states"].contains("palette")) {
149+
target->palette = *raw_section["block_states"]["palette"]
150+
.get<const std::vector<nbt::NBT> *>();
151+
const nbt::NBT::tag_long_array_t *blockStates =
152+
raw_section["block_states"]["data"]
153+
.get<const nbt::NBT::tag_long_array_t *>();
154+
155+
// Remove the air that is default-constructed
156+
target->colors.clear();
157+
// Anticipate the color input from the palette's size
158+
target->colors.reserve(target->palette.size());
159+
160+
// The length in bits of a block is the log2 of the palette's size or 4,
161+
// whichever is greatest. Ranges from 4 to 12.
162+
const uint8_t blockBitLength =
163+
std::max(uint8_t(ceil(log2(target->palette.size()))), uint8_t(4));
164+
165+
// Parse the blockstates for block info
166+
block_states_versions::post116(blockBitLength, blockStates, target->blocks);
167+
}
168+
}
169+
#endif
170+
171+
void catchall(Section *, const nbt::NBT &) {
172+
logger::deep_debug("Unsupported DataVersion\n");
173+
}
174+
} // namespace init_versions
175+
} // namespace versions
176+
} // namespace mcmap
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "../section.h"
2+
#include <stdint.h>
3+
4+
namespace mcmap {
5+
namespace versions {
6+
namespace block_states_versions {
7+
void post116(const uint8_t, const std::vector<int64_t> *,
8+
Section::block_array &);
9+
10+
void pre116(const uint8_t, const std::vector<int64_t> *,
11+
Section::block_array &);
12+
} // namespace block_states_versions
13+
14+
namespace init_versions {
15+
void v1628(Section *, const nbt::NBT &);
16+
17+
void v2534(Section *, const nbt::NBT &);
18+
19+
#ifdef SNAPSHOT_SUPPORT
20+
void v2840(Section *, const nbt::NBT &);
21+
#endif
22+
23+
void catchall(Section *, const nbt::NBT &);
24+
} // namespace init_versions
25+
} // namespace versions
26+
} // namespace mcmap

0 commit comments

Comments
 (0)