0

Merge PR #2012 from greatmastermario

This commit is contained in:
Nicolas F
2022-05-16 20:03:48 +02:00
10 changed files with 52 additions and 37 deletions

View File

@@ -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).

View File

@@ -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

View File

@@ -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;

View File

@@ -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):

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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))

View File

@@ -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