unfinished write methods for Chunk, added merge

This commit is contained in:
əlemi 2022-05-11 01:51:08 +02:00
parent bbb3848822
commit b2455a7ab8
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E

View file

@ -3,11 +3,29 @@ import math
import logging import logging
import struct import struct
from typing import Dict, Tuple, Any from typing import Dict, Tuple, Any, Optional, Iterable, List
import numpy as np import numpy as np
from aiocraft.mc.types import VarInt, Short, UnsignedByte, Type, Context from aiocraft.mc.types import VarInt, Short, UnsignedByte, UnsignedLong, Type, Context
def bit_pack(data:Iterable[int], bits:int, size:int=64):
if size <= bits:
raise ValueError("Cannot pack into chunks smaller than bits per block")
out : List[int] = []
cursor = 0
buffer = 0
for el in data:
if cursor + bits > size:
delta = (cursor+bits) - size
buffer |= (el & (2**(bits-delta) - 1)) << cursor
out.append(buffer)
buffer = 0 | (( el >> (bits-delta) ) & (2**(delta) - 1))
cursor = delta
else:
buffer |= (el & (2**bits - 1)) << cursor
cursor += bits
return out
class BitStream: class BitStream:
data : bytes data : bytes
@ -72,7 +90,11 @@ class PalettedContainer(Type):
self.size = size self.size = size
def write(self, data, buffer:io.BytesIO, ctx:Context): def write(self, data, buffer:io.BytesIO, ctx:Context):
raise NotImplementedError # TODO attempt to make a palette rather than sending always 13
UnsignedByte.write(13, buffer, ctx=ctx) # 13 bits per block
VarInt.write(0, buffer, ctx=ctx) # 0 palette len
for c in bit_pack(blocks, 13, 8*8): # FIXME add generator to iter blocks? idk
UnsignedLong.write(c, buffer, ctx=ctx)
def read(self, buffer:io.BytesIO, ctx:Context): def read(self, buffer:io.BytesIO, ctx:Context):
bits = UnsignedByte.read(buffer, ctx=ctx) # FIXME if bits > 4 it reads trash bits = UnsignedByte.read(buffer, ctx=ctx) # FIXME if bits > 4 it reads trash
@ -110,8 +132,20 @@ class HalfByteArrayType(Type):
def __init__(self, size:int): def __init__(self, size:int):
self.size = size self.size = size
def write(self, data, buffer:io.BytesIO, ctx:Context): def write(self, data:np.ndarray, buffer:io.BytesIO, ctx:Context):
raise NotImplementedError if data.shape != (self.size, self.size, self.size):
raise ValueError(f"Array must be of shape {str((self.size, self.size, self.size))}")
alternating = False
val = 0
for y in range(self.size):
for z in range(self.size):
for x in range(self.size):
if alternating:
val |= (data[x, y, z] & 0xF)
buffer.write(struct.pack("B", val)) # FIXME this format is probably wrong
else:
val |= (data[x, y, z] & 0xF) << 4
alternating = not alternating
def read(self, buffer:io.BytesIO, ctx:Context): def read(self, buffer:io.BytesIO, ctx:Context):
section = np.empty((self.size, self.size, self.size), dtype='int32') section = np.empty((self.size, self.size, self.size), dtype='int32')
@ -144,8 +178,11 @@ class NewChunkSectionType(Type):
class OldChunkSectionType(Type): class OldChunkSectionType(Type):
pytype : type pytype : type
def write(self, data, buffer:io.BytesIO, ctx:Context): def write(self, data:Tuple[np.ndarray, np.ndarray, np.ndarray], buffer:io.BytesIO, ctx:Context):
raise NotImplementedError BlockStateContainer.write(data[0], buffer, ctx=ctx)
BlockLightSection.write(data[1], buffer, ctx=ctx)
if ctx.overworld:
SkyLightSection.write(data[2], buffer, ctx=ctx)
def read(self, buffer:io.BytesIO, ctx:Context): def read(self, buffer:io.BytesIO, ctx:Context):
block_states = BlockStateContainer.read(buffer, ctx=ctx) block_states = BlockStateContainer.read(buffer, ctx=ctx)
@ -184,6 +221,13 @@ class Chunk(Type):
def __getitem__(self, item:Any): def __getitem__(self, item:Any):
return self.blocks[item] return self.blocks[item]
def merge(self, other:'Chunk'):
for i in range(16):
if not ((self.bitmask >> i) & 1):
self.blocks[:, i*16 : (i+1)*16, :] = other.blocks[:, i*16 : (i+1)*16, :]
self.block_light[:, i*16 : (i+1)*16, :] = other.block_light[:, i*16 : (i+1)*16, :]
self.sky_light[:, i*16 : (i+1)*16, :] = other.sky_light[:, i*16 : (i+1)*16, :]
def read(self, buffer:io.BytesIO, ctx:Context): def read(self, buffer:io.BytesIO, ctx:Context):
ctx.x = self.x ctx.x = self.x
ctx.z = self.z ctx.z = self.z
@ -200,6 +244,16 @@ class Chunk(Type):
logging.warning("Leftover data in chunk buffer") logging.warning("Leftover data in chunk buffer")
return self return self
def write(self, data:Any, buffer:io.BytesIO, ctx:Context):
for i in range(16):
if (self.bitmask >> i) & 1:
ChunkSection.write(
(self.blocks[:, i*16 : (i+1)*16, :], self.block_light[:, i*16 : (i+1)*16, :], self.sky_light[:, i*16 : (i+1)*16, :]),
buffer,
ctx=ctx
)
pass # TODO!!
class World: class World:
chunks : Dict[Tuple[int, int], Chunk] chunks : Dict[Tuple[int, int], Chunk]
@ -215,5 +269,7 @@ class World:
raise KeyError(f"Chunk {coord} not loaded") raise KeyError(f"Chunk {coord} not loaded")
return self.chunks[coord][int(x%16), int(y), int(z%16)] return self.chunks[coord][int(x%16), int(y), int(z%16)]
def put(self, chunk:Chunk, x:int, z:int): def put(self, chunk:Chunk, x:int, z:int, merge:bool=False):
if merge and (x,z) in self.chunks:
chunk.merge(self.chunks[(x,z)])
self.chunks[(x,z)] = chunk self.chunks[(x,z)] = chunk