Merge PR #2012 from greatmastermario
This commit is contained in:
@@ -1101,10 +1101,10 @@ Depth
|
|||||||
**Options**
|
**Options**
|
||||||
|
|
||||||
min
|
min
|
||||||
lowest level of blocks to render. Default: 0
|
lowest level of blocks to render. Default: -64
|
||||||
|
|
||||||
max
|
max
|
||||||
highest level of blocks to render. Default: 255
|
highest level of blocks to render. Default: 319
|
||||||
|
|
||||||
Exposed
|
Exposed
|
||||||
Only renders blocks that are exposed (adjacent to a transparent block).
|
Only renders blocks that are exposed (adjacent to a transparent block).
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ tiles that can be displayed with a Leaflet interface. This section goes over how
|
|||||||
Minecraft worlds work and are stored.
|
Minecraft worlds work and are stored.
|
||||||
|
|
||||||
A Minecraft world extends indefinitely along the two horizontal axes, and are
|
A Minecraft world extends indefinitely along the two horizontal axes, and are
|
||||||
exactly 256 units high. Minecraft worlds are made of voxels (volumetric pixels),
|
exactly 384 units high. Minecraft worlds are made of voxels (volumetric pixels),
|
||||||
hereby called "blocks", where each block in the world's grid has a type that
|
hereby called "blocks", where each block in the world's grid has a type that
|
||||||
determines what it is (grass, stone, ...). This makes worlds relatively
|
determines what it is (grass, stone, ...). This makes worlds relatively
|
||||||
uncomplicated to render, the Overviewer simply determines what blocks to draw
|
uncomplicated to render, the Overviewer simply determines what blocks to draw
|
||||||
@@ -40,15 +40,15 @@ iteratively.
|
|||||||
The coordinate system for Minecraft has three axes. The X and Z axes are the
|
The coordinate system for Minecraft has three axes. The X and Z axes are the
|
||||||
horizontal axes. They extend indefinitely towards both positive and negative
|
horizontal axes. They extend indefinitely towards both positive and negative
|
||||||
infinity. (There are practical limits, but no theoretical limits). The Y axis
|
infinity. (There are practical limits, but no theoretical limits). The Y axis
|
||||||
extends from 0 to 255, which corresponds with the world height limit. Each
|
extends from -64 to 319, which corresponds with the world height limit. Each
|
||||||
block in Minecraft has a coordinate address, e.g. the block at 15,78,-35 refers
|
block in Minecraft has a coordinate address, e.g. the block at 15,78,-35 refers
|
||||||
to 15 along the X axis, -35 along the Z axis, and 78 units up from bedrock.
|
to 15 along the X axis, -35 along the Z axis, and 78 units up from bedrock.
|
||||||
|
|
||||||
The world is organized in a three-layer hierarchy. At the finest level are the
|
The world is organized in a three-layer hierarchy. At the finest level are the
|
||||||
blocks (voxels). A 16x16x16 array of blocks is called a *chunk section*. A
|
blocks (voxels). A 16x16x16 array of blocks is called a *chunk section*. A
|
||||||
vertical column of 16 chunk sections makes a *chunk*. A chunk is therefore a 16
|
vertical column of 24 chunk sections makes a *chunk*. A chunk is therefore a 16
|
||||||
by 16 area of the world that extends from bedrock to sky. In other words, a 16
|
by 16 area of the world that extends from bedrock to sky. In other words, a 16
|
||||||
by 256 by 16 "chunk" of the world. A 32 by 32 area of chunks is called a
|
by 384 by 16 "chunk" of the world. A 32 by 32 area of chunks is called a
|
||||||
*region*. Regions are stored on disk one per file.
|
*region*. Regions are stored on disk one per file.
|
||||||
|
|
||||||
While blocks have a global coordinate (the ones you see in the debug output
|
While blocks have a global coordinate (the ones you see in the debug output
|
||||||
@@ -355,7 +355,8 @@ origin being at the left corner.
|
|||||||
|
|
||||||
To ensure that block closer to the viewer are drawn on top while blocks that
|
To ensure that block closer to the viewer are drawn on top while blocks that
|
||||||
should be obstructed are drawn are hidden, the blocks are drawn one layer at a
|
should be obstructed are drawn are hidden, the blocks are drawn one layer at a
|
||||||
time from bottom to top (Y=0 to Y=15) and from back to front.
|
time from bottom to top (Y=0 to Y=23, corresponding to sections Y=-4 to Y=19)
|
||||||
|
and from back to front.
|
||||||
|
|
||||||
From the data file on disk, block information in a chunk is a three-dimensional
|
From the data file on disk, block information in a chunk is a three-dimensional
|
||||||
array of bytes, each representing a `block id
|
array of bytes, each representing a `block id
|
||||||
@@ -372,12 +373,12 @@ Now that we know how to draw a single chunk, let's move on to how to place
|
|||||||
chunks relative to each other.
|
chunks relative to each other.
|
||||||
|
|
||||||
Before we get started, let's take a moment to remember that one chunk section is
|
Before we get started, let's take a moment to remember that one chunk section is
|
||||||
only 1/16th of a chunk:
|
only 1/24th of a chunk:
|
||||||
|
|
||||||
.. image:: tilerendering/entirechunk.png
|
.. image:: tilerendering/entirechunk.png
|
||||||
:alt: An entire chunk
|
:alt: An entire chunk
|
||||||
|
|
||||||
A chunk is 16 chunk sections stacked together.
|
A chunk is 24 chunk sections stacked together.
|
||||||
|
|
||||||
Since this is pretty tall, the diagrams in this section are simplified to only
|
Since this is pretty tall, the diagrams in this section are simplified to only
|
||||||
show the *top face* of a chunk, as shown in green here:
|
show the *top face* of a chunk, as shown in green here:
|
||||||
@@ -504,7 +505,7 @@ pixels.
|
|||||||
|
|
||||||
The rendering routines takes the given range of columns and rows, converts it
|
The rendering routines takes the given range of columns and rows, converts it
|
||||||
back into chunk coordinates, and renders the given 8 chunks plus all chunks from
|
back into chunk coordinates, and renders the given 8 chunks plus all chunks from
|
||||||
the 16 rows above the given range (see the note below). The chunks are
|
the 24 rows above the given range (see the note below). The chunks are
|
||||||
positioned correctly with the above positioning rules, so any chunks that are
|
positioned correctly with the above positioning rules, so any chunks that are
|
||||||
out of the bounds get rendered off the tile and don't affect the final image.
|
out of the bounds get rendered off the tile and don't affect the final image.
|
||||||
(There is therefore no penalty for rendering out-of-bounds chunks for a tile
|
(There is therefore no penalty for rendering out-of-bounds chunks for a tile
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ overviewer.util = {
|
|||||||
lat += 6 * z * perPixel;
|
lat += 6 * z * perPixel;
|
||||||
|
|
||||||
// each block down along Z adds 12px to y
|
// each block down along Z adds 12px to y
|
||||||
lat += 12 * (256 - y) * perPixel;
|
lat += 12 * (320 - y) * perPixel;
|
||||||
|
|
||||||
// add on 12 px to the X coordinate to center our point
|
// add on 12 px to the X coordinate to center our point
|
||||||
lng += 12 * perPixel;
|
lng += 12 * perPixel;
|
||||||
@@ -678,8 +678,8 @@ overviewer.util = {
|
|||||||
// only latitude and longitude, so assume Y=64. Since this is lowering
|
// only latitude and longitude, so assume Y=64. Since this is lowering
|
||||||
// down from the height of a chunk, it depends on the chunk height as
|
// down from the height of a chunk, it depends on the chunk height as
|
||||||
// so:
|
// so:
|
||||||
point.x += 256-64;
|
point.x += 320-64;
|
||||||
point.z -= 256-64;
|
point.z -= 320-64;
|
||||||
|
|
||||||
if(north_direction == overviewerConfig.CONST.UPPERRIGHT){
|
if(north_direction == overviewerConfig.CONST.UPPERRIGHT){
|
||||||
temp = point.z;
|
temp = point.z;
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ class HeightFading(RenderPrimitive):
|
|||||||
class Depth(RenderPrimitive):
|
class Depth(RenderPrimitive):
|
||||||
name = "depth"
|
name = "depth"
|
||||||
options = {
|
options = {
|
||||||
"min": ("lowest level of blocks to render", 0),
|
"min": ("lowest level of blocks to render", -64),
|
||||||
"max": ("highest level of blocks to render", 255),
|
"max": ("highest level of blocks to render", 319),
|
||||||
}
|
}
|
||||||
|
|
||||||
class Exposed(RenderPrimitive):
|
class Exposed(RenderPrimitive):
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ bool load_chunk(RenderState* state, int32_t x, int32_t z, uint8_t required) {
|
|||||||
if (!ycoord)
|
if (!ycoord)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
sectiony = PyLong_AsLong(ycoord);
|
sectiony = PyLong_AsLong(ycoord) + 4;
|
||||||
if (sectiony >= 0 && sectiony < SECTIONS_PER_CHUNK)
|
if (sectiony >= 0 && sectiony < SECTIONS_PER_CHUNK)
|
||||||
load_chunk_section(dest, sectiony, section);
|
load_chunk_section(dest, sectiony, section);
|
||||||
}
|
}
|
||||||
@@ -353,7 +353,7 @@ generate_pseudo_data(RenderState* state, uint16_t ancilData) {
|
|||||||
/* calculate the global block coordinates of this position */
|
/* calculate the global block coordinates of this position */
|
||||||
wx = (state->chunkx * 16) + x;
|
wx = (state->chunkx * 16) + x;
|
||||||
wz = (state->chunkz * 16) + z;
|
wz = (state->chunkz * 16) + z;
|
||||||
wy = (state->chunky * 16) + y;
|
wy = ((state->chunky - 4) * 16) + y;
|
||||||
/* lilypads orientation is obtained with these magic numbers */
|
/* lilypads orientation is obtained with these magic numbers */
|
||||||
/* magic numbers obtained from: */
|
/* magic numbers obtained from: */
|
||||||
/* http://llbit.se/?p=1537 */
|
/* http://llbit.se/?p=1537 */
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
// increment this value if you've made a change to the c extension
|
// increment this value if you've made a change to the c extension
|
||||||
// and want to force users to rebuild
|
// and want to force users to rebuild
|
||||||
#define OVERVIEWER_EXTENSION_VERSION 107
|
#define OVERVIEWER_EXTENSION_VERSION 109
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -78,7 +78,7 @@ PyObject* resize_half_wrap(PyObject* self, PyObject* args);
|
|||||||
typedef struct _RenderMode RenderMode;
|
typedef struct _RenderMode RenderMode;
|
||||||
|
|
||||||
/* in iterate.c */
|
/* in iterate.c */
|
||||||
#define SECTIONS_PER_CHUNK 16
|
#define SECTIONS_PER_CHUNK 24
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* whether this chunk is loaded: use load_chunk to load */
|
/* whether this chunk is loaded: use load_chunk to load */
|
||||||
int32_t loaded;
|
int32_t loaded;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ depth_start(void* data, RenderState* state, PyObject* support) {
|
|||||||
static bool
|
static bool
|
||||||
depth_hidden(void* data, RenderState* state, int32_t x, int32_t y, int32_t z) {
|
depth_hidden(void* data, RenderState* state, int32_t x, int32_t y, int32_t z) {
|
||||||
PrimitiveDepth* self = (PrimitiveDepth*)data;
|
PrimitiveDepth* self = (PrimitiveDepth*)data;
|
||||||
y += 16 * state->chunky;
|
y += 16 * (state->chunky - 4);
|
||||||
if (y > self->max || y < self->min) {
|
if (y > self->max || y < self->min) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@
|
|||||||
|
|
||||||
#include "../overviewer.h"
|
#include "../overviewer.h"
|
||||||
|
|
||||||
#define NETHER_ROOF 127
|
#define NETHER_ROOF 191
|
||||||
#define WIDTH 16
|
#define WIDTH 16
|
||||||
#define DEPTH 16
|
#define DEPTH 16
|
||||||
#define HEIGHT 256
|
#define HEIGHT 384
|
||||||
|
|
||||||
// add two to these because the primative functions should expect to
|
// add two to these because the primative functions should expect to
|
||||||
// deal with x and z values of -1 and 16
|
// deal with x and z values of -1 and 16
|
||||||
|
|||||||
@@ -92,6 +92,8 @@ do_work(workobj)
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
TILESET_VERSION = 2 # Update this whenever there is a breaking change with tile renders
|
||||||
|
|
||||||
# small but useful
|
# small but useful
|
||||||
def iterate_base4(d):
|
def iterate_base4(d):
|
||||||
"""Iterates over a base 4 number with d digits"""
|
"""Iterates over a base 4 number with d digits"""
|
||||||
@@ -309,6 +311,7 @@ class TileSet(object):
|
|||||||
|
|
||||||
self.last_rendertime = config.get('last_rendertime', 0)
|
self.last_rendertime = config.get('last_rendertime', 0)
|
||||||
self.forcerendertime = config.get('forcerendertime', 0)
|
self.forcerendertime = config.get('forcerendertime', 0)
|
||||||
|
self.lastrenderversion = config.get('lastrenderversion', 0)
|
||||||
|
|
||||||
if "renderchecks" not in self.options:
|
if "renderchecks" not in self.options:
|
||||||
# renderchecks was not given, this indicates it was not specified
|
# renderchecks was not given, this indicates it was not specified
|
||||||
@@ -318,20 +321,25 @@ class TileSet(object):
|
|||||||
# No persistent config?
|
# No persistent config?
|
||||||
if os.path.exists(self.outputdir):
|
if os.path.exists(self.outputdir):
|
||||||
# Somehow there's no config but the output dir DOES exist.
|
# Somehow there's no config but the output dir DOES exist.
|
||||||
# That's strange!
|
# That's strange! Run forcerender in case of breaking OV version change
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"For render '%s' I couldn't find any persistent config, "
|
"For render '%s' I couldn't find any persistent config, "
|
||||||
"but I did find my tile directory already exists. This "
|
"but I did find my tile directory already exists. This "
|
||||||
"shouldn't normally happen, something may be up, but I "
|
"shouldn't normally happen, something may be up, but I "
|
||||||
"think I can continue...", self.options['name'])
|
"think I can continue...", self.options['name'])
|
||||||
logging.info("Switching to --check-tiles mode")
|
logging.info("Switching to --forcerender mode")
|
||||||
self.options['renderchecks'] = 1
|
self.options['renderchecks'] = 2
|
||||||
else:
|
else:
|
||||||
# This is the typical code path for an initial render, make
|
# This is the typical code path for an initial render, make
|
||||||
# this a "forcerender"
|
# this a "forcerender"
|
||||||
self.options['renderchecks'] = 2
|
self.options['renderchecks'] = 2
|
||||||
logging.debug("This is the first time rendering %s. Doing "
|
logging.debug("This is the first time rendering %s. Doing "
|
||||||
"a full-render", self.options['name'])
|
"a full-render", self.options['name'])
|
||||||
|
elif self.lastrenderversion != TILESET_VERSION:
|
||||||
|
# Force render in case there is a version change that is breaking
|
||||||
|
logging.warning("Re-rendering world due to version change."
|
||||||
|
"This will avoid any bad rendering between incompatible versions")
|
||||||
|
self.options['renderchecks'] = 2
|
||||||
elif not os.path.exists(self.outputdir):
|
elif not os.path.exists(self.outputdir):
|
||||||
# Somehow the outputdir got erased but the metadata file is
|
# Somehow the outputdir got erased but the metadata file is
|
||||||
# still there. That's strange!
|
# still there. That's strange!
|
||||||
@@ -377,6 +385,11 @@ class TileSet(object):
|
|||||||
self.options['renderchecks'] = 2
|
self.options['renderchecks'] = 2
|
||||||
os.mkdir(self.outputdir)
|
os.mkdir(self.outputdir)
|
||||||
|
|
||||||
|
if self.lastrenderversion != TILESET_VERSION and self.options['renderchecks'] not in [2, 3]:
|
||||||
|
logging.warning("Normally renders from different versions should be"
|
||||||
|
"overridden or ignored to prevent incompatibilities,"
|
||||||
|
"but we will honor your decision.")
|
||||||
|
|
||||||
# must wait until outputdir exists
|
# must wait until outputdir exists
|
||||||
self.fs_caps = get_fs_caps(self.outputdir)
|
self.fs_caps = get_fs_caps(self.outputdir)
|
||||||
|
|
||||||
@@ -591,7 +604,8 @@ class TileSet(object):
|
|||||||
poititle=self.options.get("poititle"),
|
poititle=self.options.get("poititle"),
|
||||||
showlocationmarker=self.options.get("showlocationmarker"),
|
showlocationmarker=self.options.get("showlocationmarker"),
|
||||||
center=(self.options.get("center") or self.options.get("spawn")
|
center=(self.options.get("center") or self.options.get("spawn")
|
||||||
or [0, 64, 0])
|
or [0, 64, 0]),
|
||||||
|
lastrenderversion=TILESET_VERSION
|
||||||
)
|
)
|
||||||
d['maxZoom'] = self.options.get('maxzoom', self.treedepth)
|
d['maxZoom'] = self.options.get('maxzoom', self.treedepth)
|
||||||
if d['maxZoom'] < 0:
|
if d['maxZoom'] < 0:
|
||||||
@@ -1081,7 +1095,7 @@ class TileSet(object):
|
|||||||
max_chunk_mtime = 0
|
max_chunk_mtime = 0
|
||||||
for col, row, chunkx, chunky, chunkz, chunk_mtime in chunks:
|
for col, row, chunkx, chunky, chunkz, chunk_mtime in chunks:
|
||||||
xpos = -192 + (col - colstart) * 192
|
xpos = -192 + (col - colstart) * 192
|
||||||
ypos = -96 + (row - rowstart) * 96 + (16 - 1 - chunky) * 192
|
ypos = -96 + (row - rowstart) * 96 + (24 - 1 - chunky) * 192
|
||||||
|
|
||||||
if chunk_mtime > max_chunk_mtime:
|
if chunk_mtime > max_chunk_mtime:
|
||||||
max_chunk_mtime = chunk_mtime
|
max_chunk_mtime = chunk_mtime
|
||||||
@@ -1324,12 +1338,12 @@ def get_tiles_by_chunk(chunkcol, chunkrow):
|
|||||||
colrange = (tilecol,)
|
colrange = (tilecol,)
|
||||||
|
|
||||||
# If this chunk is in a row divisible by 4, then it touches the
|
# If this chunk is in a row divisible by 4, then it touches the
|
||||||
# tile above it as well. Also touches the next 4 tiles down (16
|
# tile above it as well. Also touches the next 6 tiles down (24
|
||||||
# rows)
|
# rows)
|
||||||
if chunkrow % 4 == 0:
|
if chunkrow % 4 == 0:
|
||||||
rowrange = range(tilerow - 4, tilerow + 32 + 1, 4)
|
rowrange = range(tilerow - 4, tilerow + 48 + 1, 4)
|
||||||
else:
|
else:
|
||||||
rowrange = range(tilerow, tilerow + 32 + 1, 4)
|
rowrange = range(tilerow, tilerow + 48 + 1, 4)
|
||||||
|
|
||||||
return product(colrange, rowrange)
|
return product(colrange, rowrange)
|
||||||
|
|
||||||
@@ -1360,12 +1374,12 @@ def get_chunks_by_tile(tile, regionset):
|
|||||||
# First do the odd. For each chunk in the tile's odd column the tile
|
# First do the odd. For each chunk in the tile's odd column the tile
|
||||||
# "passes through" three chunk sections.
|
# "passes through" three chunk sections.
|
||||||
oddcol_sections = []
|
oddcol_sections = []
|
||||||
for i, y in enumerate(reversed(range(16))):
|
for i, y in enumerate(reversed(range(24))):
|
||||||
for row in range(tile.row + 3 - i * 2, tile.row - 2 - i * 2, -2):
|
for row in range(tile.row + 3 - i * 2, tile.row - 2 - i * 2, -2):
|
||||||
oddcol_sections.append((tile.col + 1, row, y))
|
oddcol_sections.append((tile.col + 1, row, y))
|
||||||
|
|
||||||
evencol_sections = []
|
evencol_sections = []
|
||||||
for i, y in enumerate(reversed(range(16))):
|
for i, y in enumerate(reversed(range(24))):
|
||||||
for row in range(tile.row + 4 - i * 2, tile.row - 3 - i * 2, -2):
|
for row in range(tile.row + 4 - i * 2, tile.row - 3 - i * 2, -2):
|
||||||
evencol_sections.append((tile.col + 2, row, y))
|
evencol_sections.append((tile.col + 2, row, y))
|
||||||
evencol_sections.append((tile.col, row, y))
|
evencol_sections.append((tile.col, row, y))
|
||||||
|
|||||||
@@ -198,10 +198,10 @@ class World(object):
|
|||||||
disp_spawnZ = spawnZ = data['SpawnZ']
|
disp_spawnZ = spawnZ = data['SpawnZ']
|
||||||
|
|
||||||
## clamp spawnY to a sane value, in-chunk value
|
## clamp spawnY to a sane value, in-chunk value
|
||||||
if spawnY < 0:
|
if spawnY < -63:
|
||||||
spawnY = 0
|
spawnY = -63
|
||||||
if spawnY > 255:
|
if spawnY > 319:
|
||||||
spawnY = 255
|
spawnY = 319
|
||||||
|
|
||||||
## The chunk that holds the spawn location
|
## The chunk that holds the spawn location
|
||||||
chunkX = spawnX//16
|
chunkX = spawnX//16
|
||||||
@@ -236,7 +236,7 @@ class World(object):
|
|||||||
spawnY += 1
|
spawnY += 1
|
||||||
# Next section, start at local 0
|
# Next section, start at local 0
|
||||||
inChunkY = 0
|
inChunkY = 0
|
||||||
return spawnX, 256, spawnZ
|
return spawnX, 320, spawnZ
|
||||||
|
|
||||||
class RegionSet(object):
|
class RegionSet(object):
|
||||||
"""This object is the gateway to a particular Minecraft dimension within a
|
"""This object is the gateway to a particular Minecraft dimension within a
|
||||||
|
|||||||
Reference in New Issue
Block a user