Pull chunk data files over from Elektordi/pyCraft
https://github.com/Elektordi/pyCraft
This commit is contained in:
		
							
								
								
									
										0
									
								
								custom/networking/packets/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								custom/networking/packets/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								custom/networking/packets/clientbound/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								custom/networking/packets/clientbound/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
			
		||||
from minecraft.networking.packets import Packet
 | 
			
		||||
from minecraft.networking.types import (
 | 
			
		||||
    VarInt, Integer, UnsignedByte, Position, Vector, MutableRecord,
 | 
			
		||||
    attribute_alias, multi_attribute_alias,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BlockChangePacket(Packet):
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_id(context):
 | 
			
		||||
        return 0x0C if context.protocol_version >= 550 else \
 | 
			
		||||
               0x0B if context.protocol_version >= 332 else \
 | 
			
		||||
               0x0C if context.protocol_version >= 318 else \
 | 
			
		||||
               0x0B if context.protocol_version >= 67 else \
 | 
			
		||||
               0x24 if context.protocol_version >= 62 else \
 | 
			
		||||
               0x23
 | 
			
		||||
 | 
			
		||||
    packet_name = 'block change'
 | 
			
		||||
    definition = [
 | 
			
		||||
        {'location': Position},
 | 
			
		||||
        {'block_state_id': VarInt}]
 | 
			
		||||
    block_state_id = 0
 | 
			
		||||
 | 
			
		||||
    # For protocols < 347: an accessor for (block_state_id >> 4).
 | 
			
		||||
    @property
 | 
			
		||||
    def blockId(self):
 | 
			
		||||
        return self.block_state_id >> 4
 | 
			
		||||
 | 
			
		||||
    @blockId.setter
 | 
			
		||||
    def blockId(self, block_id):
 | 
			
		||||
        self.block_state_id = (self.block_state_id & 0xF) | (block_id << 4)
 | 
			
		||||
 | 
			
		||||
    # For protocols < 347: an accessor for (block_state_id & 0xF).
 | 
			
		||||
    @property
 | 
			
		||||
    def blockMeta(self):
 | 
			
		||||
        return self.block_state_id & 0xF
 | 
			
		||||
 | 
			
		||||
    @blockMeta.setter
 | 
			
		||||
    def blockMeta(self, meta):
 | 
			
		||||
        self.block_state_id = (self.block_state_id & ~0xF) | (meta & 0xF)
 | 
			
		||||
 | 
			
		||||
    # This alias is retained for backward compatibility.
 | 
			
		||||
    blockStateId = attribute_alias('block_state_id')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MultiBlockChangePacket(Packet):
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_id(context):
 | 
			
		||||
        return 0x10 if context.protocol_version >= 550 else \
 | 
			
		||||
               0x0F if context.protocol_version >= 343 else \
 | 
			
		||||
               0x10 if context.protocol_version >= 332 else \
 | 
			
		||||
               0x11 if context.protocol_version >= 318 else \
 | 
			
		||||
               0x10 if context.protocol_version >= 67 else \
 | 
			
		||||
               0x22
 | 
			
		||||
 | 
			
		||||
    packet_name = 'multi block change'
 | 
			
		||||
 | 
			
		||||
    fields = 'chunk_x', 'chunk_z', 'records'
 | 
			
		||||
 | 
			
		||||
    # Access the 'chunk_x' and 'chunk_z' fields as a tuple.
 | 
			
		||||
    chunk_pos = multi_attribute_alias(tuple, 'chunk_x', 'chunk_z')
 | 
			
		||||
 | 
			
		||||
    class Record(MutableRecord):
 | 
			
		||||
        __slots__ = 'x', 'y', 'z', 'block_state_id', 'location'
 | 
			
		||||
 | 
			
		||||
        def __init__(self, **kwds):
 | 
			
		||||
            self.block_state_id = 0
 | 
			
		||||
            super(MultiBlockChangePacket.Record, self).__init__(**kwds)
 | 
			
		||||
 | 
			
		||||
        # Access the 'x', 'y', 'z' fields as a Vector of ints.
 | 
			
		||||
        position = multi_attribute_alias(Vector, 'x', 'y', 'z')
 | 
			
		||||
 | 
			
		||||
        # For protocols < 347: an accessor for (block_state_id >> 4).
 | 
			
		||||
        @property
 | 
			
		||||
        def blockId(self):
 | 
			
		||||
            return self.block_state_id >> 4
 | 
			
		||||
 | 
			
		||||
        @blockId.setter
 | 
			
		||||
        def blockId(self, block_id):
 | 
			
		||||
            self.block_state_id = self.block_state_id & 0xF | block_id << 4
 | 
			
		||||
 | 
			
		||||
        # For protocols < 347: an accessor for (block_state_id & 0xF).
 | 
			
		||||
        @property
 | 
			
		||||
        def blockMeta(self):
 | 
			
		||||
            return self.block_state_id & 0xF
 | 
			
		||||
 | 
			
		||||
        @blockMeta.setter
 | 
			
		||||
        def blockMeta(self, meta):
 | 
			
		||||
            self.block_state_id = self.block_state_id & ~0xF | meta & 0xF
 | 
			
		||||
 | 
			
		||||
        # This alias is retained for backward compatibility.
 | 
			
		||||
        blockStateId = attribute_alias('block_state_id')
 | 
			
		||||
 | 
			
		||||
        def read(self, file_object, parent):
 | 
			
		||||
            h_position = UnsignedByte.read(file_object)
 | 
			
		||||
            self.x, self.z = h_position >> 4, h_position & 0xF
 | 
			
		||||
            self.y = UnsignedByte.read(file_object)
 | 
			
		||||
            self.block_state_id = VarInt.read(file_object)
 | 
			
		||||
            # Absolute position in world to be compatible with BlockChangePacket
 | 
			
		||||
            self.location = Vector(self.position.x + parent.chunk_x*16, self.position.y, self.position.z + parent.chunk_z*16)
 | 
			
		||||
 | 
			
		||||
        def write(self, packet_buffer):
 | 
			
		||||
            UnsignedByte.send(self.x << 4 | self.z & 0xF, packet_buffer)
 | 
			
		||||
            UnsignedByte.send(self.y, packet_buffer)
 | 
			
		||||
            VarInt.send(self.block_state_id, packet_buffer)
 | 
			
		||||
 | 
			
		||||
    def read(self, file_object):
 | 
			
		||||
        self.chunk_x = Integer.read(file_object)
 | 
			
		||||
        self.chunk_z = Integer.read(file_object)
 | 
			
		||||
        records_count = VarInt.read(file_object)
 | 
			
		||||
        self.records = []
 | 
			
		||||
        for i in range(records_count):
 | 
			
		||||
            record = self.Record()
 | 
			
		||||
            record.read(file_object, self)
 | 
			
		||||
            self.records.append(record)
 | 
			
		||||
 | 
			
		||||
    def write_fields(self, packet_buffer):
 | 
			
		||||
        Integer.send(self.chunk_x, packet_buffer)
 | 
			
		||||
        Integer.send(self.chunk_z, packet_buffer)
 | 
			
		||||
        VarInt.send(len(self.records), packet_buffer)
 | 
			
		||||
        for record in self.records:
 | 
			
		||||
            record.write(packet_buffer)
 | 
			
		||||
							
								
								
									
										139
									
								
								custom/networking/packets/clientbound/play/chunk_data.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								custom/networking/packets/clientbound/play/chunk_data.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
from math import floor
 | 
			
		||||
 | 
			
		||||
from minecraft.networking.packets import Packet, PacketBuffer
 | 
			
		||||
from minecraft.networking.types import (
 | 
			
		||||
    VarInt, Integer, Boolean, UnsignedByte, Long, Short,
 | 
			
		||||
    multi_attribute_alias, Vector, UnsignedLong
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from ....types import nbt
 | 
			
		||||
 | 
			
		||||
class ChunkDataPacket(Packet):
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get_id(context):
 | 
			
		||||
        return 0x22 # FIXME
 | 
			
		||||
 | 
			
		||||
    packet_name = 'chunk data'
 | 
			
		||||
    fields = 'x', 'bit_mask_y', 'z', 'full_chunk'
 | 
			
		||||
 | 
			
		||||
    def read(self, file_object):
 | 
			
		||||
        self.x = Integer.read(file_object)
 | 
			
		||||
        self.z = Integer.read(file_object)
 | 
			
		||||
        self.full_chunk = Boolean.read(file_object)
 | 
			
		||||
        self.bit_mask_y = VarInt.read(file_object)
 | 
			
		||||
        self.heightmaps = Nbt.read(file_object)
 | 
			
		||||
        self.biomes = []
 | 
			
		||||
        if self.full_chunk:
 | 
			
		||||
            for i in range(1024):
 | 
			
		||||
                self.biomes.append(Integer.read(file_object))
 | 
			
		||||
        size = VarInt.read(file_object)
 | 
			
		||||
        self.data = file_object.read(size)
 | 
			
		||||
        size_entities = VarInt.read(file_object)
 | 
			
		||||
        self.entities = []
 | 
			
		||||
        for i in range(size_entities):
 | 
			
		||||
            self.entities.append(Nbt.read(file_object))
 | 
			
		||||
 | 
			
		||||
        self.decode_chunk_data()
 | 
			
		||||
 | 
			
		||||
    def write_fields(self, packet_buffer):
 | 
			
		||||
        Integer.send(self.x, packet_buffer)
 | 
			
		||||
        Integer.send(self.z, packet_buffer)
 | 
			
		||||
        Boolean.send(self.full_chunk, packet_buffer)
 | 
			
		||||
        VarInt.send(self.bit_mask_y, packet_buffer)
 | 
			
		||||
        Nbt.send(self.heightmaps, packet_buffer)
 | 
			
		||||
        if self.full_chunk:
 | 
			
		||||
            for i in range(1024):
 | 
			
		||||
                Integer.send(self.biomes[i], packet_buffer)
 | 
			
		||||
        VarInt.send(len(self.data), packet_buffer)
 | 
			
		||||
        packet_buffer.send(self.data)
 | 
			
		||||
        VarInt.send(len(self.entities), packet_buffer)
 | 
			
		||||
        for e in self.entities:
 | 
			
		||||
            Nbt.send(e, packet_buffer)
 | 
			
		||||
 | 
			
		||||
    def decode_chunk_data(self):
 | 
			
		||||
        packet_data = PacketBuffer()
 | 
			
		||||
        packet_data.send(self.data)
 | 
			
		||||
        packet_data.reset_cursor()
 | 
			
		||||
 | 
			
		||||
        self.chunks = {}
 | 
			
		||||
        for i in range(16): #0-15
 | 
			
		||||
            self.chunks[i] = Chunk(self.x, i, self.z)
 | 
			
		||||
            if self.bit_mask_y & (1 << i):
 | 
			
		||||
                self.chunks[i].read(packet_data)
 | 
			
		||||
        
 | 
			
		||||
        for e in self.entities:
 | 
			
		||||
            y = e['y']
 | 
			
		||||
            self.chunks[floor(y/16)].entities.append(e)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Chunk:
 | 
			
		||||
 | 
			
		||||
    position = multi_attribute_alias(Vector, 'x', 'y', 'z')
 | 
			
		||||
 | 
			
		||||
    def __init__(self, x, y, z, empty=True):
 | 
			
		||||
        self.x = x
 | 
			
		||||
        self.y = y
 | 
			
		||||
        self.z = z
 | 
			
		||||
        self.empty = empty
 | 
			
		||||
        self.entities = []
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return 'Chunk(%r, %r, %r)' % (self.x, self.y, self.z)
 | 
			
		||||
 | 
			
		||||
    def read(self, file_object):
 | 
			
		||||
        self.empty = False
 | 
			
		||||
        self.block_count = Short.read(file_object)
 | 
			
		||||
        self.bpb = UnsignedByte.read(file_object)
 | 
			
		||||
        if self.bpb <= 4:
 | 
			
		||||
            self.bpb = 4
 | 
			
		||||
 | 
			
		||||
        if self.bpb <= 8: # Indirect palette
 | 
			
		||||
            self.palette = []
 | 
			
		||||
            size = VarInt.read(file_object)
 | 
			
		||||
            for i in range(size):
 | 
			
		||||
                self.palette.append(VarInt.read(file_object))
 | 
			
		||||
        else: # Direct palette
 | 
			
		||||
            self.palette = None
 | 
			
		||||
 | 
			
		||||
        size = VarInt.read(file_object)
 | 
			
		||||
        longs = []
 | 
			
		||||
        for i in range(size):
 | 
			
		||||
            longs.append(UnsignedLong.read(file_object))
 | 
			
		||||
 | 
			
		||||
        self.blocks = []
 | 
			
		||||
        mask = (1 << self.bpb)-1
 | 
			
		||||
        for i in range(4096):
 | 
			
		||||
            l1 = int((i*self.bpb)/64)
 | 
			
		||||
            offset = (i*self.bpb)%64
 | 
			
		||||
            l2 = int(((i+1)*self.bpb-1)/64)
 | 
			
		||||
            n = longs[l1] >> offset
 | 
			
		||||
            if l2>l1:
 | 
			
		||||
                n |= longs[l2] << (64-offset)
 | 
			
		||||
            n &= mask
 | 
			
		||||
            if self.palette:
 | 
			
		||||
                n = self.palette[n]
 | 
			
		||||
            self.blocks.append(n)
 | 
			
		||||
 | 
			
		||||
    def write_fields(self, packet_buffer):
 | 
			
		||||
        pass # TODO
 | 
			
		||||
 | 
			
		||||
    def get_block_at(self, x, y, z):
 | 
			
		||||
        if self.empty:
 | 
			
		||||
            return 0
 | 
			
		||||
        return self.blocks[x+y*256+z*16]
 | 
			
		||||
 | 
			
		||||
    def set_block_at(self, x, y, z, block):
 | 
			
		||||
        if self.empty:
 | 
			
		||||
            self.init_empty()
 | 
			
		||||
        self.blocks[x+y*256+z*16] = block
 | 
			
		||||
 | 
			
		||||
    def init_empty(self):
 | 
			
		||||
        self.blocks = []
 | 
			
		||||
        for i in range(4096):
 | 
			
		||||
            self.blocks.append(0)
 | 
			
		||||
        self.empty = False
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def origin(self):
 | 
			
		||||
        return self.position*16
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user