Info: make tile existence map mor efficient for sparse worlds

Explicitly list the coordinates where tiles exist instead of including a
full array with the size of the bounding box.
This commit is contained in:
Matthias Schiffer 2021-02-12 23:40:24 +01:00
parent 0ebc895ec0
commit d2802b73f5
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
3 changed files with 50 additions and 19 deletions

View file

@ -47,6 +47,9 @@ void Info::writeJSON(const char *filename) const {
std::fprintf(f, "\"mipmaps\":["); std::fprintf(f, "\"mipmaps\":[");
for (size_t level = 0; level < regions.size(); level++) { for (size_t level = 0; level < regions.size(); level++) {
if (level != 0)
std::fprintf(f, ",");
int minX, maxX, minZ, maxZ; int minX, maxX, minZ, maxZ;
std::tie(minX, maxX, minZ, maxZ) = getBounds(level); std::tie(minX, maxX, minZ, maxZ) = getBounds(level);
@ -57,30 +60,33 @@ void Info::writeJSON(const char *filename) const {
std::fprintf(f, "\"minZ\":%i,", minZ); std::fprintf(f, "\"minZ\":%i,", minZ);
std::fprintf(f, "\"maxZ\":%i", maxZ); std::fprintf(f, "\"maxZ\":%i", maxZ);
std::fprintf(f, "},"); std::fprintf(f, "},");
std::fprintf(f, "\"regions\":["); std::fprintf(f, "\"regions\":{");
for (int z = minZ; z <= maxZ; z++) { bool first_z = true;
std::fprintf(f, "["); for (const auto &item : regions[level]) {
if (!first_z)
std::fprintf(f, ",");
first_z = false;
for (int x = minX; x <= maxX; x++) { int z = item.first;
std::fprintf(f, "%s", regions[level].count(std::make_pair(x, z)) ? "true" : "false"); const std::set<int> &z_regions = item.second;
if (x < maxX) std::fprintf(f, "\"%d\":[", z);
bool first_x = true;
for (int x : z_regions) {
if (!first_x)
std::fprintf(f, ","); std::fprintf(f, ",");
first_x = false;
std::fprintf(f, "%d", x);
} }
if (z < maxZ) std::fprintf(f, "]");
std::fprintf(f, "],");
else
std::fprintf(f, "]");
} }
std::fprintf(f, "]"); std::fprintf(f, "}}");
if (level < regions.size() - 1)
std::fprintf(f, "},");
else
std::fprintf(f, "}");
} }
std::fprintf(f, "],"); std::fprintf(f, "],");

View file

@ -29,6 +29,7 @@
#include <climits> #include <climits>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <map>
#include <set> #include <set>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
@ -39,7 +40,7 @@ namespace MinedMap {
class Info { class Info {
private: private:
std::vector<std::set<std::pair<int, int>>> regions; std::vector<std::map<int, std::set<int>>> regions;
std::vector<std::tuple<int, int, int, int>> bounds; std::vector<std::tuple<int, int, int, int>> bounds;
int32_t spawnX, spawnZ; int32_t spawnX, spawnZ;
@ -54,7 +55,12 @@ public:
} }
void addRegion(int x, int z, size_t level) { void addRegion(int x, int z, size_t level) {
regions[level].insert(std::make_pair(x, z)); auto &level_r = regions[level];
auto z_regions = level_r.emplace(
std::piecewise_construct,
std::make_tuple(z),
std::make_tuple()).first;
z_regions->second.insert(x);
std::tuple<int, int, int, int> &b = bounds[level]; std::tuple<int, int, int, int> &b = bounds[level];

View file

@ -1,3 +1,22 @@
// bsearch-based array element check
function contains(array, elem) {
var min = 0, max = array.length, i, cur;
while (min < max) {
i = min + Math.floor((max-min)/2);
cur = array[i];
if (cur === elem)
return true;
else if (cur < elem)
min = i + 1;
else
max = i;
}
return false;
}
var MinedMapLayer = L.GridLayer.extend({ var MinedMapLayer = L.GridLayer.extend({
initialize: function (mipmaps, layer) { initialize: function (mipmaps, layer) {
this.mipmaps = mipmaps; this.mipmaps = mipmaps;
@ -43,7 +62,7 @@ var MinedMapLayer = L.GridLayer.extend({
if (coords.x >= mipmap.info.minX && coords.x <= mipmap.info.maxX && if (coords.x >= mipmap.info.minX && coords.x <= mipmap.info.maxX &&
coords.y >= mipmap.info.minZ && coords.y <= mipmap.info.maxZ && coords.y >= mipmap.info.minZ && coords.y <= mipmap.info.maxZ &&
mipmap.regions[coords.y-mipmap.info.minZ][coords.x-mipmap.info.minX]) contains(mipmap.regions[coords.y] || [], coords.x))
tile.src = 'data/'+this.layer+'/'+z+'/r.'+coords.x+'.'+coords.y+'.png'; tile.src = 'data/'+this.layer+'/'+z+'/r.'+coords.x+'.'+coords.y+'.png';
if (z === 0) if (z === 0)