Skip to content

Bugfix/#2003 #1954 1.18 increased height #2012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4 changes: 2 additions & 2 deletions docs/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1101,10 +1101,10 @@ Depth
**Options**

min
lowest level of blocks to render. Default: 0
lowest level of blocks to render. Default: -64

max
highest level of blocks to render. Default: 255
highest level of blocks to render. Default: 319

Exposed
Only renders blocks that are exposed (adjacent to a transparent block).
Expand Down
17 changes: 9 additions & 8 deletions docs/design/designdoc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tiles that can be displayed with a Leaflet interface. This section goes over how
Minecraft worlds work and are stored.

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
determines what it is (grass, stone, ...). This makes worlds relatively
uncomplicated to render, the Overviewer simply determines what blocks to draw
Expand All @@ -40,15 +40,15 @@ iteratively.
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
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
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
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 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.

While blocks have a global coordinate (the ones you see in the debug output
Expand Down Expand Up @@ -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
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
array of bytes, each representing a `block id
Expand All @@ -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.

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
: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
show the *top face* of a chunk, as shown in green here:
Expand Down Expand Up @@ -504,7 +505,7 @@ pixels.

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
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
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
Expand Down
6 changes: 3 additions & 3 deletions overviewer_core/data/js_src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ overviewer.util = {
lat += 6 * z * perPixel;

// 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
lng += 12 * perPixel;
Expand Down Expand Up @@ -678,8 +678,8 @@ overviewer.util = {
// 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
// so:
point.x += 256-64;
point.z -= 256-64;
point.x += 320-64;
point.z -= 320-64;

if(north_direction == overviewerConfig.CONST.UPPERRIGHT){
temp = point.z;
Expand Down
4 changes: 2 additions & 2 deletions overviewer_core/rendermodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ class HeightFading(RenderPrimitive):
class Depth(RenderPrimitive):
name = "depth"
options = {
"min": ("lowest level of blocks to render", 0),
"max": ("highest level of blocks to render", 255),
"min": ("lowest level of blocks to render", -64),
"max": ("highest level of blocks to render", 319),
}

class Exposed(RenderPrimitive):
Expand Down
4 changes: 2 additions & 2 deletions overviewer_core/src/iterate.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ bool load_chunk(RenderState* state, int32_t x, int32_t z, uint8_t required) {
if (!ycoord)
continue;

sectiony = PyLong_AsLong(ycoord);
sectiony = PyLong_AsLong(ycoord) + 4;
if (sectiony >= 0 && sectiony < SECTIONS_PER_CHUNK)
load_chunk_section(dest, sectiony, section);
}
Expand Down Expand Up @@ -353,7 +353,7 @@ generate_pseudo_data(RenderState* state, uint16_t ancilData) {
/* calculate the global block coordinates of this position */
wx = (state->chunkx * 16) + x;
wz = (state->chunkz * 16) + z;
wy = (state->chunky * 16) + y;
wy = ((state->chunky - 4) * 16) + y;
/* lilypads orientation is obtained with these magic numbers */
/* magic numbers obtained from: */
/* http://llbit.se/?p=1537 */
Expand Down
4 changes: 2 additions & 2 deletions overviewer_core/src/overviewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

// increment this value if you've made a change to the c extension
// and want to force users to rebuild
#define OVERVIEWER_EXTENSION_VERSION 107
#define OVERVIEWER_EXTENSION_VERSION 108

#include <stdbool.h>
#include <stdint.h>
Expand Down Expand Up @@ -78,7 +78,7 @@ PyObject* resize_half_wrap(PyObject* self, PyObject* args);
typedef struct _RenderMode RenderMode;

/* in iterate.c */
#define SECTIONS_PER_CHUNK 16
#define SECTIONS_PER_CHUNK 24
typedef struct {
/* whether this chunk is loaded: use load_chunk to load */
int32_t loaded;
Expand Down
2 changes: 1 addition & 1 deletion overviewer_core/src/primitives/depth.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ depth_start(void* data, RenderState* state, PyObject* support) {
static bool
depth_hidden(void* data, RenderState* state, int32_t x, int32_t y, int32_t z) {
PrimitiveDepth* self = (PrimitiveDepth*)data;
y += 16 * state->chunky;
y += 16 * (state->chunky - 4);
if (y > self->max || y < self->min) {
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions overviewer_core/src/primitives/nether.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@

#include "../overviewer.h"

#define NETHER_ROOF 127
#define NETHER_ROOF 191
#define WIDTH 16
#define DEPTH 16
#define HEIGHT 256
#define HEIGHT 384

// add two to these because the primative functions should expect to
// deal with x and z values of -1 and 16
Expand Down
34 changes: 24 additions & 10 deletions overviewer_core/tileset.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@
"""


TILESET_VERSION = 2 # Update this whenever there is a breaking change with tile renders

# small but useful
def iterate_base4(d):
"""Iterates over a base 4 number with d digits"""
Expand Down Expand Up @@ -309,6 +311,7 @@ def __init__(self, worldobj, regionsetobj, assetmanagerobj, texturesobj, options

self.last_rendertime = config.get('last_rendertime', 0)
self.forcerendertime = config.get('forcerendertime', 0)
self.lastrenderversion = config.get('lastrenderversion', 0)

if "renderchecks" not in self.options:
# renderchecks was not given, this indicates it was not specified
Expand All @@ -318,20 +321,25 @@ def __init__(self, worldobj, regionsetobj, assetmanagerobj, texturesobj, options
# No persistent config?
if os.path.exists(self.outputdir):
# 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(
"For render '%s' I couldn't find any persistent config, "
"but I did find my tile directory already exists. This "
"shouldn't normally happen, something may be up, but I "
"think I can continue...", self.options['name'])
logging.info("Switching to --check-tiles mode")
self.options['renderchecks'] = 1
logging.info("Switching to --forcerender mode")
self.options['renderchecks'] = 2
else:
# This is the typical code path for an initial render, make
# this a "forcerender"
self.options['renderchecks'] = 2
logging.debug("This is the first time rendering %s. Doing "
"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):
# Somehow the outputdir got erased but the metadata file is
# still there. That's strange!
Expand Down Expand Up @@ -377,6 +385,11 @@ def __init__(self, worldobj, regionsetobj, assetmanagerobj, texturesobj, options
self.options['renderchecks'] = 2
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
self.fs_caps = get_fs_caps(self.outputdir)

Expand Down Expand Up @@ -591,7 +604,8 @@ def bgcolorformat(color):
poititle=self.options.get("poititle"),
showlocationmarker=self.options.get("showlocationmarker"),
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)
if d['maxZoom'] < 0:
Expand Down Expand Up @@ -1081,7 +1095,7 @@ def _render_rendertile(self, tile):
max_chunk_mtime = 0
for col, row, chunkx, chunky, chunkz, chunk_mtime in chunks:
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:
max_chunk_mtime = chunk_mtime
Expand Down Expand Up @@ -1324,12 +1338,12 @@ def get_tiles_by_chunk(chunkcol, chunkrow):
colrange = (tilecol,)

# 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)
if chunkrow % 4 == 0:
rowrange = range(tilerow - 4, tilerow + 32 + 1, 4)
rowrange = range(tilerow - 4, tilerow + 48 + 1, 4)
else:
rowrange = range(tilerow, tilerow + 32 + 1, 4)
rowrange = range(tilerow, tilerow + 48 + 1, 4)

return product(colrange, rowrange)

Expand Down Expand Up @@ -1360,12 +1374,12 @@ def get_mtime(x, y):
# First do the odd. For each chunk in the tile's odd column the tile
# "passes through" three chunk 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):
oddcol_sections.append((tile.col + 1, row, y))

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):
evencol_sections.append((tile.col + 2, row, y))
evencol_sections.append((tile.col, row, y))
Expand Down
10 changes: 5 additions & 5 deletions overviewer_core/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,10 @@ def find_true_spawn(self):
disp_spawnZ = spawnZ = data['SpawnZ']

## clamp spawnY to a sane value, in-chunk value
if spawnY < 0:
spawnY = 0
if spawnY > 255:
spawnY = 255
if spawnY < -63:
spawnY = -63
if spawnY > 319:
spawnY = 319
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the spawnY < 0 check should also be updated to -64?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent point. I forgot to take that into account. Let me fix that.


## The chunk that holds the spawn location
chunkX = spawnX//16
Expand Down Expand Up @@ -236,7 +236,7 @@ def find_true_spawn(self):
spawnY += 1
# Next section, start at local 0
inChunkY = 0
return spawnX, 256, spawnZ
return spawnX, 320, spawnZ

class RegionSet(object):
"""This object is the gateway to a particular Minecraft dimension within a
Expand Down