PyAnvilEditor
PyAnvilEditor copied to clipboard
Propose fix to make it compatible with MC 1.16
TL;DR In 1.16, chunk format changed slightly, I rewrote a function so that reading works again in 1.16. I'm not used to github, so the code is simply pasted below.
Since snapshot 20w19a, block states are no longer stored directly after each other, which used to result in misalignment and some values being split over multiple longs. Now each long stores as much block states as possible, pads the rest with zeroes, and the next values are aligned perfectly from the start of the next long. The current version of PyAnvilEditor isn't updated for this and reads misaligned data when unpacking a chun k(sometimes throwing index out of range errors). I rewrote a function so that it could now read blocks without errors in 1.16
To fix: Replace"_read_width_from_loc" in world.py with:
def _read_width_from_loc(long_list, width, position):
#max amount of blockstates that fit in each long
states_per_long = 64 // width
#the long in which this blockstate is stored
long_index = position // states_per_long
#at which bit in the long this state is located
position_in_long = (position % states_per_long)*width
return Chunk._read_bits(long_list[long_index], width, position_in_long)
also the minimum width is 4 bits, so "width = max(width,4)" could be added. source: https://minecraft.gamepedia.com/Chunk_format#Block_format (at BlockStates)
I changed the serialize _blockstates function in world.py too, so now writing blocks works again and the enitre library should be compatible with 1.16, I haven't run into any problems at least. Update it to this:
def _serialize_blockstates(self, state_mapping):
serial_states = nbt.LongArrayTag(tag_name='BlockStates')
width = math.ceil(math.log(len(self.palette), 2))
if width < 4:
width = 4
#max amount of states that fit in a long
states_per_long = 64 // width
#amount of longs
arraylength = math.ceil(len(self.blocks) / states_per_long)
for long_index in range(arraylength):
lng = 0
for state in range(states_per_long):
#insert blocks in reverse, so first one ends up most to the right
block_index = long_index*states_per_long + (states_per_long - state - 1)
if block_index < len(self.blocks):
block = self.blocks[block_index]
lng = (lng << width) + state_mapping[block._state]
lng = int.from_bytes(lng.to_bytes(8, byteorder='big', signed=False), byteorder='big', signed=True)
serial_states.add_child(nbt.LongTag(lng))
return serial_states