biomes now work, still no swamp purple though
This commit is contained in:
@@ -146,9 +146,9 @@ int load_chunk(RenderState* state, int x, int z, unsigned char required) {
|
|||||||
if (sections) {
|
if (sections) {
|
||||||
sections = PySequence_Fast(sections, "Sections tag was not a list!");
|
sections = PySequence_Fast(sections, "Sections tag was not a list!");
|
||||||
}
|
}
|
||||||
Py_DECREF(chunk);
|
|
||||||
if (sections == NULL) {
|
if (sections == NULL) {
|
||||||
// exception set, again
|
// exception set, again
|
||||||
|
Py_DECREF(chunk);
|
||||||
if (!required) {
|
if (!required) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
@@ -156,6 +156,7 @@ int load_chunk(RenderState* state, int x, int z, unsigned char required) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* set up reasonable defaults */
|
/* set up reasonable defaults */
|
||||||
|
dest->biomes = NULL;
|
||||||
for (i = 0; i < SECTIONS_PER_CHUNK; i++)
|
for (i = 0; i < SECTIONS_PER_CHUNK; i++)
|
||||||
{
|
{
|
||||||
dest->sections[i].blocks = NULL;
|
dest->sections[i].blocks = NULL;
|
||||||
@@ -164,6 +165,9 @@ int load_chunk(RenderState* state, int x, int z, unsigned char required) {
|
|||||||
dest->sections[i].blocklight = NULL;
|
dest->sections[i].blocklight = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dest->biomes = PyDict_GetItemString(chunk, "Biomes");
|
||||||
|
Py_INCREF(dest->biomes);
|
||||||
|
|
||||||
for (i = 0; i < PySequence_Fast_GET_SIZE(sections); i++) {
|
for (i = 0; i < PySequence_Fast_GET_SIZE(sections); i++) {
|
||||||
PyObject *ycoord = NULL;
|
PyObject *ycoord = NULL;
|
||||||
int sectiony = 0;
|
int sectiony = 0;
|
||||||
@@ -177,6 +181,7 @@ int load_chunk(RenderState* state, int x, int z, unsigned char required) {
|
|||||||
load_chunk_section(dest, sectiony, section);
|
load_chunk_section(dest, sectiony, section);
|
||||||
}
|
}
|
||||||
Py_DECREF(sections);
|
Py_DECREF(sections);
|
||||||
|
Py_DECREF(chunk);
|
||||||
|
|
||||||
dest->loaded = 1;
|
dest->loaded = 1;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -573,6 +578,7 @@ chunk_render(PyObject *self, PyObject *args) {
|
|||||||
for (j = 0; j < 3; j++) {
|
for (j = 0; j < 3; j++) {
|
||||||
if (state.chunks[i][j].loaded) {
|
if (state.chunks[i][j].loaded) {
|
||||||
int k;
|
int k;
|
||||||
|
Py_XDECREF(state.chunks[i][j].biomes);
|
||||||
for (k = 0; k < SECTIONS_PER_CHUNK; k++) {
|
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].blocks);
|
||||||
Py_XDECREF(state.chunks[i][j].sections[k].data);
|
Py_XDECREF(state.chunks[i][j].sections[k].data);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
// increment this value if you've made a change to the c extesion
|
// increment this value if you've made a change to the c extesion
|
||||||
// and want to force users to rebuild
|
// and want to force users to rebuild
|
||||||
#define OVERVIEWER_EXTENSION_VERSION 24
|
#define OVERVIEWER_EXTENSION_VERSION 25
|
||||||
|
|
||||||
/* Python PIL, and numpy headers */
|
/* Python PIL, and numpy headers */
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
@@ -38,11 +38,13 @@
|
|||||||
in y/z/x order */
|
in y/z/x order */
|
||||||
#define getArrayByte3D(array, x,y,z) (*(unsigned char *)(PyArray_GETPTR3((array), (y), (z), (x))))
|
#define getArrayByte3D(array, x,y,z) (*(unsigned char *)(PyArray_GETPTR3((array), (y), (z), (x))))
|
||||||
#define getArrayShort3D(array, x,y,z) (*(unsigned short *)(PyArray_GETPTR3((array), (y), (z), (x))))
|
#define getArrayShort3D(array, x,y,z) (*(unsigned short *)(PyArray_GETPTR3((array), (y), (z), (x))))
|
||||||
|
#define getArrayByte2D(array, x,y) (*(unsigned char *)(PyArray_GETPTR2((array), (x), (y))))
|
||||||
#define getArrayShort2D(array, x,y) (*(unsigned short *)(PyArray_GETPTR2((array), (x), (y))))
|
#define getArrayShort2D(array, x,y) (*(unsigned short *)(PyArray_GETPTR2((array), (x), (y))))
|
||||||
|
|
||||||
/* generally useful MAX / MIN macros */
|
/* generally useful MAX / MIN macros */
|
||||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define CLAMP(x, a, b) (MIN(MAX(x, a), b))
|
||||||
|
|
||||||
/* in composite.c */
|
/* in composite.c */
|
||||||
Imaging imaging_python_to_c(PyObject *obj);
|
Imaging imaging_python_to_c(PyObject *obj);
|
||||||
@@ -71,6 +73,8 @@ typedef struct _RenderMode RenderMode;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
/* whether this chunk is loaded: use load_chunk to load */
|
/* whether this chunk is loaded: use load_chunk to load */
|
||||||
int loaded;
|
int loaded;
|
||||||
|
/* chunk biome array */
|
||||||
|
PyObject *biomes;
|
||||||
/* all the sections in a given chunk */
|
/* all the sections in a given chunk */
|
||||||
struct {
|
struct {
|
||||||
/* all there is to know about each section */
|
/* all there is to know about each section */
|
||||||
@@ -143,6 +147,7 @@ typedef enum
|
|||||||
DATA,
|
DATA,
|
||||||
BLOCKLIGHT,
|
BLOCKLIGHT,
|
||||||
SKYLIGHT,
|
SKYLIGHT,
|
||||||
|
BIOMES,
|
||||||
} DataType;
|
} DataType;
|
||||||
static inline unsigned int get_data(RenderState *state, DataType type, int x, int y, int z)
|
static inline unsigned int get_data(RenderState *state, DataType type, int x, int y, int z)
|
||||||
{
|
{
|
||||||
@@ -198,6 +203,8 @@ static inline unsigned int get_data(RenderState *state, DataType type, int x, in
|
|||||||
case SKYLIGHT:
|
case SKYLIGHT:
|
||||||
data_array = state->chunks[chunkx][chunkz].sections[chunky].skylight;
|
data_array = state->chunks[chunkx][chunkz].sections[chunky].skylight;
|
||||||
break;
|
break;
|
||||||
|
case BIOMES:
|
||||||
|
data_array = state->chunks[chunkx][chunkz].biomes;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data_array == NULL)
|
if (data_array == NULL)
|
||||||
@@ -205,6 +212,8 @@ static inline unsigned int get_data(RenderState *state, DataType type, int x, in
|
|||||||
|
|
||||||
if (type == BLOCKS)
|
if (type == BLOCKS)
|
||||||
return getArrayShort3D(data_array, x, y, z);
|
return getArrayShort3D(data_array, x, y, z);
|
||||||
|
if (type == BIOMES)
|
||||||
|
return getArrayByte2D(data_array, x, z);
|
||||||
return getArrayByte3D(data_array, x, y, z);
|
return getArrayByte3D(data_array, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,30 +18,68 @@
|
|||||||
#include "../overviewer.h"
|
#include "../overviewer.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* biome data for the chunk */
|
|
||||||
PyObject *biome_data;
|
|
||||||
/* grasscolor and foliagecolor lookup tables */
|
/* grasscolor and foliagecolor lookup tables */
|
||||||
PyObject *grasscolor, *foliagecolor, *watercolor;
|
PyObject *grasscolor, *foliagecolor, *watercolor;
|
||||||
/* biome-compatible grass/leaf textures */
|
/* biome-compatible grass/leaf textures */
|
||||||
PyObject *grass_texture;
|
PyObject *grass_texture;
|
||||||
} PrimitiveBase;
|
} PrimitiveBase;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
float temperature;
|
||||||
|
float rainfall;
|
||||||
|
} Biome;
|
||||||
|
|
||||||
|
/* each entry in this table is yanked *directly* out of the minecraft source
|
||||||
|
* temp/rainfall are taken from what MCP calls setTemperatureRainfall
|
||||||
|
*
|
||||||
|
* keep in mind the x/y coordinate in the color tables is found *after*
|
||||||
|
* multiplying rainfall and temperature for the second coordinate, *and* the
|
||||||
|
* origin is in the lower-right. <3 biomes.
|
||||||
|
*/
|
||||||
|
static Biome biome_table[] = {
|
||||||
|
/* 0 */
|
||||||
|
{"Ocean", 0.5, 0.5},
|
||||||
|
{"Plains", 0.8, 0.4},
|
||||||
|
{"Desert", 2.0, 0.0},
|
||||||
|
{"Extreme Hills", 0.2, 0.3},
|
||||||
|
{"Forest", 0.7, 0.8},
|
||||||
|
/* 5 */
|
||||||
|
{"Taiga", 0.05, 0.8},
|
||||||
|
{"Swampland", 0.8, 0.9},
|
||||||
|
{"River", 0.5, 0.5},
|
||||||
|
{"Hell", 2.0, 0.0},
|
||||||
|
{"Sky", 0.5, 0.5},
|
||||||
|
/* 10 */
|
||||||
|
{"FrozenOcean", 0.0, 0.5},
|
||||||
|
{"FrozenRiver", 0.0, 0.5},
|
||||||
|
{"Ice Plains", 0.0, 0.5},
|
||||||
|
{"Ice Mountains", 0.0, 0.5},
|
||||||
|
{"MushroomIsland", 0.9, 1.0},
|
||||||
|
/* 15 */
|
||||||
|
{"MushroomIslandShore", 0.9, 1.0},
|
||||||
|
{"Beach", 0.8, 0.4},
|
||||||
|
{"DesertHills", 2.0, 0.0},
|
||||||
|
{"ForestHills", 0.7, 0.8},
|
||||||
|
{"TaigaHills", 0.05, 0.8},
|
||||||
|
/* 20 */
|
||||||
|
{"Extreme Hills Edge", 0.2, 0.3},
|
||||||
|
{"Jungle", 2.0, 0.45}, /* <-- GUESS, but a good one */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUM_BIOMES (sizeof(biome_table) / sizeof(Biome))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
base_start(void *data, RenderState *state, PyObject *support) {
|
base_start(void *data, RenderState *state, PyObject *support) {
|
||||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||||
|
|
||||||
/* biome-compliant grass mask (includes sides!) */
|
/* biome-compliant grass mask (includes sides!) */
|
||||||
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
self->grass_texture = PyObject_GetAttrString(state->textures, "biome_grass_texture");
|
||||||
|
|
||||||
self->biome_data = PyObject_CallMethod(state->regionset, "get_biome_data", "ii", state->chunkx, state->chunkz);
|
/* color lookup tables */
|
||||||
if (self->biome_data == NULL) {
|
self->foliagecolor = PyObject_CallMethod(state->textures, "load_foliage_color", "");
|
||||||
/* error while loading biome info, or no biomes at all */
|
self->grasscolor = PyObject_CallMethod(state->textures, "load_grass_color", "");
|
||||||
PyErr_Clear();
|
self->watercolor = PyObject_CallMethod(state->textures, "load_water_color", "");
|
||||||
} else {
|
|
||||||
self->foliagecolor = PyObject_CallMethod(state->textures, "load_foliage_color", "");
|
|
||||||
self->grasscolor = PyObject_CallMethod(state->textures, "load_grass_color", "");
|
|
||||||
self->watercolor = PyObject_CallMethod(state->textures, "load_water_color", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -50,11 +88,10 @@ static void
|
|||||||
base_finish(void *data, RenderState *state) {
|
base_finish(void *data, RenderState *state) {
|
||||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||||
|
|
||||||
Py_XDECREF(self->biome_data);
|
Py_DECREF(self->foliagecolor);
|
||||||
Py_XDECREF(self->foliagecolor);
|
Py_DECREF(self->grasscolor);
|
||||||
Py_XDECREF(self->grasscolor);
|
Py_DECREF(self->watercolor);
|
||||||
Py_XDECREF(self->watercolor);
|
Py_DECREF(self->grass_texture);
|
||||||
Py_XDECREF(self->grass_texture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -72,13 +109,6 @@ base_occluded(void *data, RenderState *state, int x, int y, int z) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
base_hidden(void *data, RenderState *state, int x, int y, int z) {
|
|
||||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObject *mask_light) {
|
||||||
PrimitiveBase *self = (PrimitiveBase *)data;
|
PrimitiveBase *self = (PrimitiveBase *)data;
|
||||||
@@ -91,9 +121,8 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
|
|||||||
* NOTES for maintainers:
|
* NOTES for maintainers:
|
||||||
*
|
*
|
||||||
* To add a biome-compatible block, add an OR'd condition to this
|
* To add a biome-compatible block, add an OR'd condition to this
|
||||||
* following if block, a case to the first switch statement to handle when
|
* following if block, and a case to the switch statement to handle biome
|
||||||
* biome info IS available, and another case to the second switch
|
* coloring.
|
||||||
* statement for when biome info ISN'T available.
|
|
||||||
*
|
*
|
||||||
* Make sure that in textures.py, the generated textures are the
|
* Make sure that in textures.py, the generated textures are the
|
||||||
* biome-compliant ones! The tinting is now all done here.
|
* biome-compliant ones! The tinting is now all done here.
|
||||||
@@ -116,113 +145,102 @@ base_draw(void *data, RenderState *state, PyObject *src, PyObject *mask, PyObjec
|
|||||||
{
|
{
|
||||||
/* do the biome stuff! */
|
/* do the biome stuff! */
|
||||||
PyObject *facemask = mask;
|
PyObject *facemask = mask;
|
||||||
unsigned char r, g, b;
|
unsigned char r = 255, g = 255, b = 255;
|
||||||
|
PyObject *color_table = NULL;
|
||||||
|
unsigned char flip_xy = 0;
|
||||||
|
|
||||||
if (state->block == 2) {
|
if (state->block == 2) {
|
||||||
/* grass needs a special facemask */
|
/* grass needs a special facemask */
|
||||||
facemask = self->grass_texture;
|
facemask = self->grass_texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->biome_data) {
|
switch (state->block) {
|
||||||
/* we have data, so use it! */
|
case 2:
|
||||||
unsigned int index;
|
/* grass */
|
||||||
|
color_table = self->grasscolor;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
case 9:
|
||||||
|
/* water */
|
||||||
|
color_table = self->watercolor;
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
/* leaves */
|
||||||
|
color_table = self->foliagecolor;
|
||||||
|
if (state->block_data == 2)
|
||||||
|
{
|
||||||
|
/* birch!
|
||||||
|
birch foliage color is flipped XY-ways */
|
||||||
|
flip_xy = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
/* tall grass */
|
||||||
|
color_table = self->grasscolor;
|
||||||
|
break;
|
||||||
|
case 104:
|
||||||
|
/* pumpkin stem */
|
||||||
|
color_table = self->grasscolor;
|
||||||
|
break;
|
||||||
|
case 105:
|
||||||
|
/* melon stem */
|
||||||
|
color_table = self->grasscolor;
|
||||||
|
break;
|
||||||
|
case 106:
|
||||||
|
/* vines */
|
||||||
|
color_table = self->grasscolor;
|
||||||
|
break;
|
||||||
|
case 111:
|
||||||
|
/* lily pads */
|
||||||
|
color_table = self->grasscolor;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (color_table) {
|
||||||
|
int dx, dz;
|
||||||
|
unsigned char tablex, tabley;
|
||||||
|
float temp = 0.0, rain = 0.0;
|
||||||
PyObject *color = NULL;
|
PyObject *color = NULL;
|
||||||
|
|
||||||
index = big_endian_ushort(getArrayShort2D(self->biome_data, state->x, state->y));
|
/* average over all neighbors */
|
||||||
|
for (dx = -1; dx <= 1; dx++) {
|
||||||
switch (state->block) {
|
for (dz = -1; dz <= 1; dz += (dx == 0 ? 2 : 1)) {
|
||||||
case 2:
|
unsigned char biome = get_data(state, BIOMES, state->x + dx, state->y, state->z + dz);
|
||||||
/* grass */
|
if (biome > NUM_BIOMES)
|
||||||
color = PySequence_GetItem(self->grasscolor, index);
|
biome = 0;
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
case 9:
|
|
||||||
/* water */
|
|
||||||
if (self->watercolor)
|
|
||||||
{
|
|
||||||
color = PySequence_GetItem(self->watercolor, index);
|
|
||||||
} else {
|
|
||||||
color = NULL;
|
|
||||||
facemask = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 18:
|
|
||||||
/* leaves */
|
|
||||||
if (state->block_data != 2)
|
|
||||||
{
|
|
||||||
/* not birch! */
|
|
||||||
color = PySequence_GetItem(self->foliagecolor, index);
|
|
||||||
} else {
|
|
||||||
/* birch!
|
|
||||||
birch foliage color is flipped XY-ways */
|
|
||||||
unsigned int index_x = 255 - (index % 256);
|
|
||||||
unsigned int index_y = 255 - (index / 256);
|
|
||||||
index = index_y * 256 + index_x;
|
|
||||||
|
|
||||||
color = PySequence_GetItem(self->foliagecolor, index);
|
temp += biome_table[biome].temperature;
|
||||||
|
rain += biome_table[biome].rainfall;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 31:
|
|
||||||
/* tall grass */
|
|
||||||
color = PySequence_GetItem(self->grasscolor, index);
|
|
||||||
break;
|
|
||||||
case 104:
|
|
||||||
/* pumpkin stem */
|
|
||||||
color = PySequence_GetItem(self->grasscolor, index);
|
|
||||||
break;
|
|
||||||
case 105:
|
|
||||||
/* melon stem */
|
|
||||||
color = PySequence_GetItem(self->grasscolor, index);
|
|
||||||
break;
|
|
||||||
case 106:
|
|
||||||
/* vines */
|
|
||||||
color = PySequence_GetItem(self->grasscolor, index);
|
|
||||||
break;
|
|
||||||
case 111:
|
|
||||||
/* lily pads */
|
|
||||||
color = PySequence_GetItem(self->grasscolor, index);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (color)
|
|
||||||
{
|
|
||||||
/* we've got work to do */
|
|
||||||
|
|
||||||
r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0));
|
|
||||||
g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
|
|
||||||
b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
|
||||||
Py_DECREF(color);
|
|
||||||
}
|
}
|
||||||
} else {
|
temp /= 8.0;
|
||||||
if (state->block == 2 || state->block == 31 ||
|
rain /= 8.0;
|
||||||
state->block == 104 || state->block == 105)
|
|
||||||
/* grass and pumpkin/melon stems */
|
/* make sure they're sane */
|
||||||
{
|
temp = CLAMP(temp, 0.0, 1.0);
|
||||||
r = 115;
|
rain = CLAMP(rain, 0.0, 1.0);
|
||||||
g = 175;
|
|
||||||
b = 71;
|
/* convert to x/y coordinates in color table */
|
||||||
|
tablex = 255 - (255 * temp);
|
||||||
|
tabley = 255 - (255 * temp * rain);
|
||||||
|
if (flip_xy) {
|
||||||
|
unsigned char tmp = 255 - tablex;
|
||||||
|
tablex = 255 - tabley;
|
||||||
|
tabley = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->block == 8 || state->block == 9)
|
/* look up color! */
|
||||||
/* water */
|
color = PySequence_GetItem(color_table, tabley * 256 + tablex);
|
||||||
{
|
r = PyInt_AsLong(PyTuple_GET_ITEM(color, 0));
|
||||||
/* by default water is fine with nothing */
|
g = PyInt_AsLong(PyTuple_GET_ITEM(color, 1));
|
||||||
facemask = NULL;
|
b = PyInt_AsLong(PyTuple_GET_ITEM(color, 2));
|
||||||
}
|
Py_DECREF(color);
|
||||||
|
|
||||||
if (state->block == 18 || state->block == 106 || state->block == 111)
|
|
||||||
/* leaves, vines and lyli pads */
|
|
||||||
{
|
|
||||||
r = 37;
|
|
||||||
g = 118;
|
|
||||||
b = 25;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (facemask)
|
/* final coloration */
|
||||||
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
|
tint_with_mask(state->img, r, g, b, 255, facemask, state->imgx, state->imgy, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +249,6 @@ RenderPrimitiveInterface primitive_base = {
|
|||||||
base_start,
|
base_start,
|
||||||
base_finish,
|
base_finish,
|
||||||
base_occluded,
|
base_occluded,
|
||||||
base_hidden,
|
NULL,
|
||||||
base_draw,
|
base_draw,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,14 +32,11 @@ This module has routines for extracting information about available worlds
|
|||||||
class ChunkDoesntExist(Exception):
|
class ChunkDoesntExist(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class BiomeDataDoesntExist(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def log_other_exceptions(func):
|
def log_other_exceptions(func):
|
||||||
"""A decorator that prints out any errors that are not
|
"""A decorator that prints out any errors that are not
|
||||||
ChunkDoesntExist or BiomeDataDoesntExist errors. This decorates
|
ChunkDoesntExist errors. This decorates get_chunk because the C
|
||||||
get_chunk because the C code is likely to swallow exceptions, so
|
code is likely to swallow exceptions, so this will at least make
|
||||||
this will at least make them visible.
|
them visible.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
functools.wraps(func)
|
functools.wraps(func)
|
||||||
@@ -48,8 +45,6 @@ def log_other_exceptions(func):
|
|||||||
return func(*args)
|
return func(*args)
|
||||||
except ChunkDoesntExist:
|
except ChunkDoesntExist:
|
||||||
raise
|
raise
|
||||||
except BiomeDataDoesntExist:
|
|
||||||
raise
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
logging.exception("%s raised this exception", func.func_name)
|
logging.exception("%s raised this exception", func.func_name)
|
||||||
raise
|
raise
|
||||||
@@ -239,7 +234,6 @@ class RegionSet(object):
|
|||||||
|
|
||||||
# Caching implementaiton: a simple LRU cache
|
# Caching implementaiton: a simple LRU cache
|
||||||
# Decorate the getter methods with the cache decorator
|
# Decorate the getter methods with the cache decorator
|
||||||
self._get_biome_data_for_region = cache.lru_cache(cachesize)(self._get_biome_data_for_region)
|
|
||||||
self.get_chunk = cache.lru_cache(cachesize)(self.get_chunk)
|
self.get_chunk = cache.lru_cache(cachesize)(self.get_chunk)
|
||||||
|
|
||||||
# Re-initialize upon unpickling
|
# Re-initialize upon unpickling
|
||||||
@@ -264,45 +258,6 @@ class RegionSet(object):
|
|||||||
else:
|
else:
|
||||||
raise Exception("Woah, what kind of dimension is this! %r" % self.regiondir)
|
raise Exception("Woah, what kind of dimension is this! %r" % self.regiondir)
|
||||||
|
|
||||||
# this is decorated with cache.lru_cache in __init__(). Be aware!
|
|
||||||
@log_other_exceptions
|
|
||||||
def _get_biome_data_for_region(self, regionx, regionz):
|
|
||||||
"""Get the block of biome data for an entire region. Biome
|
|
||||||
data is in the format output by Minecraft Biome Extractor:
|
|
||||||
http://code.google.com/p/minecraft-biome-extractor/"""
|
|
||||||
|
|
||||||
# biomes only make sense for the overworld, right now
|
|
||||||
if self.get_type() != "overworld":
|
|
||||||
raise BiomeDataDoesntExist("Biome data is not available for '%s'." % (self.get_type(),))
|
|
||||||
|
|
||||||
# biomes are, unfortunately, in a different place than regiondir
|
|
||||||
biomefile = os.path.split(self.regiondir)[0]
|
|
||||||
biomefile = os.path.join(biomefile, 'biomes', 'b.%d.%d.biome' % (regionx, regionz))
|
|
||||||
|
|
||||||
try:
|
|
||||||
with open(biomefile, 'rb') as f:
|
|
||||||
data = f.read()
|
|
||||||
if not len(data) == 512 * 512 * 2:
|
|
||||||
raise BiomeDataDoesntExist("File `%s' does not have correct size." % (biomefile,))
|
|
||||||
data = numpy.frombuffer(data, dtype=numpy.dtype(">u2"))
|
|
||||||
# reshape and transpose to get [x, z] indices
|
|
||||||
return numpy.transpose(numpy.reshape(data, (512, 512)))
|
|
||||||
except IOError:
|
|
||||||
raise BiomeDataDoesntExist("File `%s' could not be read." % (biomefile,))
|
|
||||||
|
|
||||||
@log_other_exceptions
|
|
||||||
def get_biome_data(self, x, z):
|
|
||||||
"""Get the block of biome data for the given chunk. Biome data
|
|
||||||
is returned as a 16x16 numpy array of indices into the
|
|
||||||
corresponding biome color images."""
|
|
||||||
regionx = x // 32
|
|
||||||
regionz = z // 32
|
|
||||||
blockx = (x % 32) * 16
|
|
||||||
blockz = (z % 32) * 16
|
|
||||||
|
|
||||||
region_biomes = self._get_biome_data_for_region(regionx, regionz)
|
|
||||||
return region_biomes[blockx:blockx+16,blockz:blockz+16]
|
|
||||||
|
|
||||||
# this is decorated with cache.lru_cache in __init__(). Be aware!
|
# this is decorated with cache.lru_cache in __init__(). Be aware!
|
||||||
@log_other_exceptions
|
@log_other_exceptions
|
||||||
def get_chunk(self, x, z):
|
def get_chunk(self, x, z):
|
||||||
@@ -507,11 +462,6 @@ class RotatedRegionSet(RegionSet):
|
|||||||
def __setstate__(self, args):
|
def __setstate__(self, args):
|
||||||
self.__init__(args[0], args[1])
|
self.__init__(args[0], args[1])
|
||||||
|
|
||||||
def get_biome_data(self, x, z):
|
|
||||||
x,z = self.unrotate(x,z)
|
|
||||||
biome_data = super(RotatedRegionSet, self).get_biome_data(x,z)
|
|
||||||
return numpy.rot90(biome_data, self.north_dir)
|
|
||||||
|
|
||||||
def get_chunk(self, x, z):
|
def get_chunk(self, x, z):
|
||||||
x,z = self.unrotate(x,z)
|
x,z = self.unrotate(x,z)
|
||||||
chunk_data = super(RotatedRegionSet, self).get_chunk(x,z)
|
chunk_data = super(RotatedRegionSet, self).get_chunk(x,z)
|
||||||
|
|||||||
Reference in New Issue
Block a user