Skip to content
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

Fix dark chunks - addresses #2029 and #1899, prepares for fix of #2002, #2024, and #2035 #2060

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 47 additions & 29 deletions overviewer_core/world.py
Original file line number Diff line number Diff line change
Expand Up @@ -1711,39 +1711,48 @@ def get_chunk(self, x, z):
chunk_data['NewBiomes'] = (len(biomes.shape) == 3)

unrecognized_block_types = {}
for section in chunk_data['Sections']:

# Turn the skylight array into a 16x16x16 matrix. The array comes
# packed 2 elements per byte, so we need to expand it.
sections = chunk_data['Sections']
# Sometimes, Minecraft loves generating chunks with no light info.
# These mostly appear to have those two properties, and in this case
# we default to full-bright as it's less jarring to look at than all-black.
fullbright = chunk_data.get("Status", "") == "spawn" and 'Lights' in chunk_data
if not fullbright and self.get_type() is None:
# In the overworld, we also default to fullbright if these is no sky light
# in the chunk at full level.
# We can't just check for the complete absence of light, as Minecraft will
# sometimes partially generate sky light in chunks that is just spillover
# from neighboring chunks, but doesn't take the chunk itself into account,
# leaving us with a mostly dark chunk.
# The nice thing about sky light that spills over is, it is never at full
# level.
# Also, almost all chunks will have full sky light at the very top.
# Therefore: if a chunk contains sky light, but none of it is full, we can
# be 99% sure that that chunk is one of these mostly dark ones.
# If you've built a roof of leaves at build limit and are reading this:
# I'm sorry.
for section in sections[::-1]:
if "SkyLight" in section:
light = numpy.frombuffer(section["SkyLight"], dtype=numpy.uint8)
if numpy.any((light>>4) == 15) or numpy.any((light & 15) == 15):
break
else:
fullbright = True

for section in sections:
try:
# Sometimes, Minecraft loves generating chunks with no light info.
# These mostly appear to have those two properties, and in this case
# we default to full-bright as it's less jarring to look at than all-black.
if chunk_data.get("Status", "") == "spawn" and 'Lights' in chunk_data:
if fullbright:
section['SkyLight'] = numpy.full((16,16,16), 255, dtype=numpy.uint8)
elif not "SkyLight" in section:
# Special case introduced with 1.14
section['SkyLight'] = numpy.zeros((16,16,16), dtype=numpy.uint8)
else:
if 'SkyLight' in section:
skylight = numpy.frombuffer(section['SkyLight'], dtype=numpy.uint8)
skylight = skylight.reshape((16,16,8))
else: # Special case introduced with 1.14
skylight = numpy.zeros((16,16,8), dtype=numpy.uint8)
skylight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8)
skylight_expanded[:,:,::2] = skylight & 0x0F
skylight_expanded[:,:,1::2] = (skylight & 0xF0) >> 4
del skylight
section['SkyLight'] = skylight_expanded

# Turn the BlockLight array into a 16x16x16 matrix, same as SkyLight
if 'BlockLight' in section:
blocklight = numpy.frombuffer(section['BlockLight'], dtype=numpy.uint8)
blocklight = blocklight.reshape((16,16,8))
else: # Special case introduced with 1.14
blocklight = numpy.zeros((16,16,8), dtype=numpy.uint8)
blocklight_expanded = numpy.empty((16,16,16), dtype=numpy.uint8)
blocklight_expanded[:,:,::2] = blocklight & 0x0F
blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4
del blocklight
section['BlockLight'] = blocklight_expanded
section['SkyLight'] = self._extract_light_data(section["SkyLight"])

if not 'BlockLight' in section:
section['BlockLight'] = numpy.zeros((16,16,16), dtype=numpy.uint8)
else:
section['BlockLight'] = self._extract_light_data(section["BlockLight"])

if 'block_states' in section:
(blocks, data) = self._get_blockdata_v118(section, unrecognized_block_types, longarray_unpacker)
Expand All @@ -1769,6 +1778,15 @@ def get_chunk(self, x, z):

return chunk_data

def _extract_light_data(self, data):
# Turn the light array into a 16x16x16 matrix. The array comes
# packed 2 elements per byte, so we need to expand it.
light = numpy.frombuffer(data, dtype=numpy.uint8).reshape((16,16,8))
light_expanded = numpy.empty((16,16,16), dtype=numpy.uint8)
light_expanded[:,:,::2] = light & 0x0F
light_expanded[:,:,1::2] = (light & 0xF0) >> 4
del light
return light_expanded

def iterate_chunks(self):
"""Returns an iterator over all chunk metadata in this world. Iterates
Expand Down