0

Translate to old map format

For now, this will only work with palette indices up to 8 bits.
(Support for palette indices up to 12 bits should follow.)
This commit is contained in:
gmcnew
2018-08-05 23:57:12 +00:00
parent a61131dc4f
commit e10b2f8960

View File

@@ -328,6 +328,85 @@ class RegionSet(object):
region = nbt.load_region(regionfilename) region = nbt.load_region(regionfilename)
self.regioncache[regionfilename] = region self.regioncache[regionfilename] = region
return region return region
def _packed_longarray_to_shorts(self, long_array, n):
bits_per_value = (len(long_array) * 64) / n
if bits_per_value < 4 or 8 < bits_per_value:
raise nbt.CorruptChunkError()
b = numpy.frombuffer(numpy.asarray(long_array), dtype=numpy.uint8)
if bits_per_value == 8:
result = b.astype(numpy.uint16)
else:
result = []
i = 0
# We will consume the byte array in chunks equal to bits_per_value.
while i < len(b):
if bits_per_value == 4:
for k in range(0, 4):
result.extend([
b[i + k] & 0x0f,
(b[i + k] & 0xf0) >> 4,
])
i += 4
elif bits_per_value == 5:
result.extend([
b[i] & 0x1f,
((b[i+1] & 0x03) << 3) | ((b[i] & 0xe0) >> 5),
(b[i+1] & 0x7c) >> 2,
((b[i+2] & 0x0f) << 1) | ((b[i+1] & 0x80) >> 7),
((b[i+3] & 0x01) << 4) | ((b[i+2] & 0xf0) >> 4),
(b[i+3] & 0x3e) >> 1,
((b[i+4] & 0x07) << 2) | ((b[i+3] & 0xc0) >> 6),
(b[i+4] & 0xf8) >> 3,
])
i += 5
elif bits_per_value == 6:
result.extend([
b[i] & 0x3f,
((b[i+1] & 0x0f) << 2) | ((b[i] & 0xc0) >> 6),
((b[i+2] & 0x03) << 4) | ((b[i+1] & 0xf0) >> 4),
(b[i+2] & 0xfc) >> 2,
])
i += 3
elif bits_per_value == 7:
result.extend([
b[i] & 0x7f,
((b[i+1] & 0x3f) << 1) | ((b[i] & 0x80) >> 7),
((b[i+2] & 0x1f) << 2) | ((b[i+1] & 0xc0) >> 6),
((b[i+3] & 0x0f) << 3) | ((b[i+2] & 0xe0) >> 5),
((b[i+4] & 0x07) << 4) | ((b[i+3] & 0xf0) >> 4),
((b[i+5] & 0x03) << 5) | ((b[i+4] & 0xf8) >> 3),
((b[i+6] & 0x01) << 6) | ((b[i+5] & 0xfc) >> 2),
(b[i+6] & 0xfc) >> 1,
])
i += 7
else:
i += bits_per_value
result = numpy.asarray(result, numpy.uint16)
return result
def get_block_and_data(self, palette_entry):
blockmap = {
'minecraft:stone': (1, 0),
'minecraft:air': (0, 0),
'minecraft:diorite': (1, 3),
'minecraft:bedrock': (7, 0),
'minecraft:dirt': (3, 0),
'minecraft:andesite': (1, 5),
'minecraft:granite': (1, 1),
'minecraft:cave_air': (0, 0),
'minecraft:gravel': (13, 0),
'minecraft:grass_block': (2, 0),
'minecraft:snow': (78, 0),
'minecraft:coal_ore': (16, 0),
'minecraft:iron_ore': (15, 0),
'minecraft:redstone_ore': (73, 0),
'minecraft:lava': (10, 0),
'minecraft:grass': (175, 2),
'minecraft:gold_ore': (14, 0),
}
return blockmap.get(palette_entry['Name'], (0, 0)) # default to air
#@log_other_exceptions #@log_other_exceptions
def get_chunk(self, x, z): def get_chunk(self, x, z):
@@ -405,36 +484,27 @@ class RegionSet(object):
chunk_data = level chunk_data = level
# Turn the Biomes array into a 16x16 numpy array # Turn the Biomes array into a 16x16 numpy array
try: biomes = numpy.asarray(chunk_data['Biomes'])
biomes = numpy.frombuffer(chunk_data['Biomes'], dtype=numpy.uint8) if len(biomes) == 0:
biomes = biomes.reshape((16,16))
except KeyError:
# worlds converted by Jeb's program may be missing the Biomes key
biomes = numpy.zeros((16, 16), dtype=numpy.uint8) biomes = numpy.zeros((16, 16), dtype=numpy.uint8)
else:
biomes = biomes.reshape((16,16))
chunk_data['Biomes'] = biomes chunk_data['Biomes'] = biomes
for section in chunk_data['Sections']: for section in chunk_data['Sections']:
# Turn the BlockStates array into a 16x16x16 numpy matrix of shorts.
block_states = self._packed_longarray_to_shorts(section['BlockStates'], 4096)
blocks = numpy.zeros((4096,), dtype=numpy.uint16)
data = numpy.zeros((4096,), dtype=numpy.uint8)
for i in range(len(block_states)):
palette_entry = section['Palette'][block_states[i]]
(blocks[i], data[i]) = self.get_block_and_data(palette_entry)
# Turn the Blocks array into a 16x16x16 numpy matrix of shorts, # Turn the Data array into a 16x16x16 matrix, same as SkyLight
# adding in the additional block array if included. section['Blocks'] = blocks.reshape((16, 16, 16))
blocks = numpy.frombuffer(section['Blocks'], dtype=numpy.uint8) section['Data'] = data.reshape((16, 16, 16))
# Cast up to uint16, blocks can have up to 12 bits of data del blocks
blocks = blocks.astype(numpy.uint16) del data
blocks = blocks.reshape((16,16,16))
if "Add" in section:
# This section has additional bits to tack on to the blocks
# array. Add is a packed array with 4 bits per slot, so
# it needs expanding
additional = numpy.frombuffer(section['Add'], dtype=numpy.uint8)
additional = additional.astype(numpy.uint16).reshape((16,16,8))
additional_expanded = numpy.empty((16,16,16), dtype=numpy.uint16)
additional_expanded[:,:,::2] = (additional & 0x0F) << 8
additional_expanded[:,:,1::2] = (additional & 0xF0) << 4
blocks += additional_expanded
del additional
del additional_expanded
del section['Add'] # Save some memory
section['Blocks'] = blocks
# Turn the skylight array into a 16x16x16 matrix. The array comes # Turn the skylight array into a 16x16x16 matrix. The array comes
# packed 2 elements per byte, so we need to expand it. # packed 2 elements per byte, so we need to expand it.
@@ -455,15 +525,6 @@ class RegionSet(object):
blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4 blocklight_expanded[:,:,1::2] = (blocklight & 0xF0) >> 4
del blocklight del blocklight
section['BlockLight'] = blocklight_expanded section['BlockLight'] = blocklight_expanded
# Turn the Data array into a 16x16x16 matrix, same as SkyLight
data = numpy.frombuffer(section['Data'], dtype=numpy.uint8)
data = data.reshape((16,16,8))
data_expanded = numpy.empty((16,16,16), dtype=numpy.uint8)
data_expanded[:,:,::2] = data & 0x0F
data_expanded[:,:,1::2] = (data & 0xF0) >> 4
del data
section['Data'] = data_expanded
except ValueError: except ValueError:
# iv'e seen at least 1 case where numpy raises a value error during the reshapes. i'm not # iv'e seen at least 1 case where numpy raises a value error during the reshapes. i'm not
# sure what's going on here, but let's treat this as a corrupt chunk error # sure what's going on here, but let's treat this as a corrupt chunk error