improved world data reading, still broken
This commit is contained in:
parent
9ac4a844cf
commit
22ae0b9f3a
1 changed files with 60 additions and 30 deletions
|
@ -24,15 +24,23 @@ class BitStream:
|
||||||
def read(self, size:int) -> int:
|
def read(self, size:int) -> int:
|
||||||
if len(self) < size:
|
if len(self) < size:
|
||||||
raise ValueError(f"Not enough bits ({len(self)} left, {size} requested)")
|
raise ValueError(f"Not enough bits ({len(self)} left, {size} requested)")
|
||||||
|
# Calculate splice indexes
|
||||||
start_byte = (self.cursor//8)
|
start_byte = (self.cursor//8)
|
||||||
end_byte = math.ceil((self.cursor + size) / 8) + 1
|
end_byte = math.ceil((self.cursor + size) / 8)
|
||||||
|
# Construct int from bytes
|
||||||
buf = int.from_bytes(
|
buf = int.from_bytes(
|
||||||
self.data[start_byte:end_byte],
|
self.data[start_byte:end_byte],
|
||||||
byteorder='little', signed=False
|
byteorder='little', signed=False
|
||||||
)
|
)
|
||||||
cut_right = 8 - ((self.cursor + size) % 8)
|
# Trim extra bytes
|
||||||
|
end_offset = (self.cursor + size) % 8
|
||||||
|
if end_offset > 0:
|
||||||
|
buf = buf >> (8 - end_offset) # There's an extra 1 to the left in air, maybe shift 1 bit less?
|
||||||
|
start_offset = self.cursor % 8
|
||||||
|
buf = buf & (( 1 << size ) - 1)
|
||||||
|
# Increment and return
|
||||||
self.cursor += size
|
self.cursor += size
|
||||||
return ( buf >> cut_right ) & ( 0xFF >> (8 - (size%8)))
|
return buf
|
||||||
|
|
||||||
class PalettedContainer(Type):
|
class PalettedContainer(Type):
|
||||||
pytype : type
|
pytype : type
|
||||||
|
@ -47,29 +55,56 @@ class PalettedContainer(Type):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def read(self, buffer:io.BytesIO, ctx:Context):
|
def read(self, buffer:io.BytesIO, ctx:Context):
|
||||||
bits = max(UnsignedByte.read(buffer, ctx=ctx), 4)
|
bits = UnsignedByte.read(buffer, ctx=ctx)
|
||||||
if bits > 13:
|
logging.info("Bits per block : %d", bits)
|
||||||
raise ValueError("Bits Per Bit too high : %d", bits)
|
if bits < 4:
|
||||||
palette = np.empty((0,), dtype='int32')
|
bits = 4
|
||||||
|
if bits >= self.threshold:
|
||||||
|
bits = 13 # this should not be hardcoded but we have no way to calculate all possible block states
|
||||||
palette_len = VarInt.read(buffer, ctx=ctx)
|
palette_len = VarInt.read(buffer, ctx=ctx)
|
||||||
if bits < self.threshold:
|
|
||||||
palette = np.zeros((palette_len,), dtype='int32')
|
palette = np.zeros((palette_len,), dtype='int32')
|
||||||
for i in range(palette_len):
|
for i in range(palette_len):
|
||||||
palette[i] = VarInt.read(buffer, ctx=ctx)
|
palette[i] = VarInt.read(buffer, ctx=ctx)
|
||||||
size = VarInt.read(buffer, ctx=ctx)
|
container_size = VarInt.read(buffer, ctx=ctx)
|
||||||
stream = BitStream(buffer.read(size * 8), size*8*8) # a Long is 64 bits long
|
stream = BitStream(buffer.read(container_size * 8), container_size*8*8) # a Long is 64 bits long
|
||||||
section = np.zeros((self.size, self.size, self.size), dtype='int32')
|
section = np.zeros((self.size, self.size, self.size), dtype='int32')
|
||||||
index = 0
|
|
||||||
for y in range(self.size):
|
for y in range(self.size):
|
||||||
for z in range(self.size):
|
for z in range(self.size):
|
||||||
for x in range(self.size):
|
for x in range(self.size):
|
||||||
val = stream.read(bits)
|
val = stream.read(bits)
|
||||||
|
if bits > 4:
|
||||||
|
if val >= len(palette):
|
||||||
|
logging.warning("out of bounds : %d (%d)", val, len(palette))
|
||||||
|
section[x, y, z] = val
|
||||||
|
continue
|
||||||
|
logging.info("Reading index when bits > 4")
|
||||||
section[x, y, z] = palette[val] if bits < self.threshold else val
|
section[x, y, z] = palette[val] if bits < self.threshold else val
|
||||||
return section
|
return section
|
||||||
|
|
||||||
BiomeContainer = PalettedContainer(4, 4)
|
BiomeContainer = PalettedContainer(4, 4)
|
||||||
BlockStateContainer = PalettedContainer(9, 16)
|
BlockStateContainer = PalettedContainer(9, 16)
|
||||||
|
|
||||||
|
class HalfByteArrayType(Type):
|
||||||
|
size : int
|
||||||
|
|
||||||
|
def __init__(self, size:int):
|
||||||
|
self.size = size
|
||||||
|
|
||||||
|
def write(self, data, buffer:io.BytesIO, ctx:Context):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def read(self, buffer:io.BytesIO, ctx:Context):
|
||||||
|
section = np.empty((self.size, self.size, self.size), dtype='int32')
|
||||||
|
bit_buffer = BitStream(buffer.read((self.size**3)//2), (self.size**3)*4)
|
||||||
|
for y in range(self.size):
|
||||||
|
for z in range(self.size):
|
||||||
|
for x in range(self.size):
|
||||||
|
section[x, y, z] = bit_buffer.read(4)
|
||||||
|
return section
|
||||||
|
|
||||||
|
BlockLightSection = HalfByteArrayType(16)
|
||||||
|
SkyLightSection = HalfByteArrayType(16)
|
||||||
|
|
||||||
class NewChunkSectionType(Type):
|
class NewChunkSectionType(Type):
|
||||||
pytype : type
|
pytype : type
|
||||||
|
|
||||||
|
@ -93,22 +128,14 @@ class OldChunkSectionType(Type):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def read(self, buffer:io.BytesIO, ctx:Context):
|
def read(self, buffer:io.BytesIO, ctx:Context):
|
||||||
section = BlockStateContainer.read(buffer, ctx=ctx)
|
block_states = BlockStateContainer.read(buffer, ctx=ctx)
|
||||||
block_light = np.empty((16, 16, 16), dtype='int32')
|
block_light = BlockLightSection.read(buffer, ctx=ctx)
|
||||||
block_light_buffer = BitStream(buffer.read(2048), 2048*8)
|
|
||||||
for y in range(16):
|
|
||||||
for z in range(16):
|
|
||||||
for x in range(16):
|
|
||||||
block_light[x, y, z] = block_light_buffer.read(4)
|
|
||||||
sky_light = np.empty((16, 16, 16), dtype='int32')
|
|
||||||
if ctx.overworld:
|
if ctx.overworld:
|
||||||
sky_light_buffer = BitStream(buffer.read(2048), 2048*8)
|
sky_light = SkyLightSection.read(buffer, ctx=ctx)
|
||||||
for y in range(16):
|
else:
|
||||||
for z in range(16):
|
sky_light = np.empty((16, 16, 16), dtype='int32')
|
||||||
for x in range(16):
|
|
||||||
sky_light[x, y, z] = sky_light_buffer.read(4)
|
|
||||||
return (
|
return (
|
||||||
section,
|
block_states,
|
||||||
block_light,
|
block_light,
|
||||||
sky_light
|
sky_light
|
||||||
)
|
)
|
||||||
|
@ -142,12 +169,15 @@ class Chunk(Type):
|
||||||
logging.info("Reading chunk")
|
logging.info("Reading chunk")
|
||||||
for i in range(16):
|
for i in range(16):
|
||||||
if (self.bitmask >> i) & 1:
|
if (self.bitmask >> i) & 1:
|
||||||
section, block_light, sky_light = ChunkSection.read(buffer, ctx=ctx)
|
logging.info("Reading section #%d", i)
|
||||||
self.blocks[:, i*16 : (i+1)*16, :] = section
|
block_states, block_light, sky_light = ChunkSection.read(buffer, ctx=ctx)
|
||||||
|
self.blocks[:, i*16 : (i+1)*16, :] = block_states
|
||||||
self.block_light[:, i*16 : (i+1)*16, :] = block_light
|
self.block_light[:, i*16 : (i+1)*16, :] = block_light
|
||||||
self.sky_light[:, i*16 : (i+1)*16, :] = sky_light
|
self.sky_light[:, i*16 : (i+1)*16, :] = sky_light
|
||||||
if self.ground_up_continuous:
|
if self.ground_up_continuous:
|
||||||
self.biomes = buffer.read(256) # 16x16
|
self.biomes = buffer.read(256) # 16x16
|
||||||
|
if buffer.read():
|
||||||
|
logging.warning("Leftover data in chunk buffer")
|
||||||
return self
|
return self
|
||||||
|
|
||||||
class World:
|
class World:
|
||||||
|
|
Loading…
Reference in a new issue