diff --git a/overviewer_core/biome.py b/overviewer_core/biome.py
new file mode 100644
index 0000000..8d79ef3
--- /dev/null
+++ b/overviewer_core/biome.py
@@ -0,0 +1,40 @@
+# This file is part of the Minecraft Overviewer.
+#
+# Minecraft Overviewer is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or (at
+# your option) any later version.
+#
+# Minecraft Overviewer is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details, and note that Jeffrey Epstein didn't kill
+# himself.
+#
+# You should have received a copy of the GNU General Public License along
+# with the Overviewer. If not, see .
+
+import numpy
+
+class BiomeDispensary:
+ """Turns biome arrays of either 256 or 1024 integer values into 16x16 2d arrays,
+ which can then be retrieved for any Y level with get_biome.
+ """
+ def __init__(self, biome_array):
+ self.biome_len = len(biome_array)
+ if self.biome_len == 256:
+ self.biomes = [biome_array.reshape((16, 16))]
+ elif self.biome_len == 1024:
+ self.biomes = [None] * 4
+ for i in range(0, 4):
+ # Map 256 values of the array to each self.biomes entry, resulting
+ # in 4 entries
+ self.biomes[i] = biome_array[i * 256:(i + 1) * 256].reshape((16, 16))
+
+ def get_biome(self, y_level):
+ if y_level < 0:
+ return None
+ if self.biome_len == 256:
+ return self.biomes[0]
+ else:
+ return self.biomes[y_level // 4]
diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c
index 5fc9b5b..99a8b3d 100644
--- a/overviewer_core/src/iterate.c
+++ b/overviewer_core/src/iterate.c
@@ -109,10 +109,12 @@ static inline void load_chunk_section(ChunkData* dest, int32_t i, PyObject* sect
dest->sections[i].data = (PyArrayObject*)PyDict_GetItemString(section, "Data");
dest->sections[i].skylight = (PyArrayObject*)PyDict_GetItemString(section, "SkyLight");
dest->sections[i].blocklight = (PyArrayObject*)PyDict_GetItemString(section, "BlockLight");
+ dest->sections[i].biomes = (PyArrayObject*)PyDict_GetItemString(section, "Biomes");
Py_INCREF(dest->sections[i].blocks);
Py_INCREF(dest->sections[i].data);
Py_INCREF(dest->sections[i].skylight);
Py_INCREF(dest->sections[i].blocklight);
+ Py_INCREF(dest->sections[i].biomes);
}
/* loads the given chunk into the chunks[] array in the state
@@ -130,13 +132,12 @@ bool load_chunk(RenderState* state, int32_t x, int32_t z, uint8_t required) {
if (dest->loaded)
return false;
- /* set up reasonable defaults */
- dest->biomes = NULL;
for (i = 0; i < SECTIONS_PER_CHUNK; i++) {
dest->sections[i].blocks = NULL;
dest->sections[i].data = NULL;
dest->sections[i].skylight = NULL;
dest->sections[i].blocklight = NULL;
+ dest->sections[i].biomes = NULL;
}
dest->loaded = 1;
@@ -166,8 +167,6 @@ bool load_chunk(RenderState* state, int32_t x, int32_t z, uint8_t required) {
return true;
}
- dest->biomes = (PyArrayObject*)PyDict_GetItemString(chunk, "Biomes");
- Py_INCREF(dest->biomes);
for (i = 0; i < PySequence_Fast_GET_SIZE(sections); i++) {
PyObject* ycoord = NULL;
@@ -194,12 +193,12 @@ unload_all_chunks(RenderState* state) {
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++) {
if (state->chunks[i][j].loaded) {
- Py_XDECREF(state->chunks[i][j].biomes);
for (k = 0; k < SECTIONS_PER_CHUNK; k++) {
Py_XDECREF(state->chunks[i][j].sections[k].blocks);
Py_XDECREF(state->chunks[i][j].sections[k].data);
Py_XDECREF(state->chunks[i][j].sections[k].skylight);
Py_XDECREF(state->chunks[i][j].sections[k].blocklight);
+ Py_XDECREF(state->chunks[i][j].sections[k].biomes);
}
state->chunks[i][j].loaded = 0;
}
diff --git a/overviewer_core/src/overviewer.h b/overviewer_core/src/overviewer.h
index 7e450dc..8cac99d 100644
--- a/overviewer_core/src/overviewer.h
+++ b/overviewer_core/src/overviewer.h
@@ -31,7 +31,7 @@
// increment this value if you've made a change to the c extesion
// and want to force users to rebuild
-#define OVERVIEWER_EXTENSION_VERSION 77
+#define OVERVIEWER_EXTENSION_VERSION 78
#include
#include
@@ -87,7 +87,7 @@ typedef struct {
/* all the sections in a given chunk */
struct {
/* all there is to know about each section */
- PyArrayObject *blocks, *data, *skylight, *blocklight;
+ PyArrayObject *blocks, *data, *skylight, *blocklight, *biomes;
} sections[SECTIONS_PER_CHUNK];
} ChunkData;
typedef struct {
@@ -210,7 +210,7 @@ static inline uint32_t get_data(RenderState* state, DataType type, int32_t x, in
data_array = state->chunks[chunkx][chunkz].sections[chunky].skylight;
break;
case BIOMES:
- data_array = state->chunks[chunkx][chunkz].biomes;
+ data_array = state->chunks[chunkx][chunkz].sections[chunky].biomes;
};
if (data_array == NULL)
diff --git a/overviewer_core/world.py b/overviewer_core/world.py
index ae88913..d5fe11a 100644
--- a/overviewer_core/world.py
+++ b/overviewer_core/world.py
@@ -26,6 +26,7 @@ import numpy
from . import nbt
from . import cache
+from .biome import BiomeDispensary
"""
This module has routines for extracting information about available worlds
@@ -1370,13 +1371,15 @@ class RegionSet(object):
biomes = numpy.frombuffer(biomes, dtype=numpy.uint8)
else:
biomes = numpy.asarray(biomes)
- biomes = biomes.reshape((16,16))
+ #biomes = biomes.reshape((16,16))
+ biome_giver = BiomeDispensary(biomes)
else:
# Worlds converted by Jeb's program may be missing the Biomes key.
# Additionally, 19w09a worlds have an empty array as biomes key
# in some cases.
- biomes = numpy.zeros((16, 16), dtype=numpy.uint8)
- chunk_data['Biomes'] = biomes
+ #biomes = numpy.zeros((16, 16), dtype=numpy.uint8)
+ biome_giver = BiomeDispensary(numpy.zeros(256, dtype=numpy.uint8))
+ #chunk_data['Biomes'] = biomes
unrecognized_block_types = {}
for section in chunk_data['Sections']:
@@ -1384,6 +1387,7 @@ class RegionSet(object):
# Turn the skylight array into a 16x16x16 matrix. The array comes
# packed 2 elements per byte, so we need to expand it.
try:
+ section['Biomes'] = biome_giver.get_biome(section["Y"])
if 'SkyLight' in section:
skylight = numpy.frombuffer(section['SkyLight'], dtype=numpy.uint8)
skylight = skylight.reshape((16,16,8))
@@ -1607,6 +1611,9 @@ class RotatedRegionSet(RegionSetWrapper):
for section in chunk_data['Sections']:
section = dict(section)
newsections.append(section)
+ biomes = numpy.swapaxes(section['Biomes'], 0, 1)
+ biomes = numpy.rot90(biomes, self.north_dir)
+ section['Biomes'] = numpy.swapaxes(biomes, 0, 1)
for arrayname in ['Blocks', 'Data', 'SkyLight', 'BlockLight']:
array = section[arrayname]
# Since the anvil change, arrays are arranged with axes Y,Z,X
@@ -1619,9 +1626,6 @@ class RotatedRegionSet(RegionSetWrapper):
chunk_data['Sections'] = newsections
# same as above, for biomes (Z/X indexed)
- biomes = numpy.swapaxes(chunk_data['Biomes'], 0, 1)
- biomes = numpy.rot90(biomes, self.north_dir)
- chunk_data['Biomes'] = numpy.swapaxes(biomes, 0, 1)
return chunk_data
def get_chunk_mtime(self, x, z):