From 8fabe5859a795dfb1f34b81b9791c058a738c34b Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Tue, 8 Sep 2020 20:13:15 -0600 Subject: [PATCH] Simplify directory structure --- bot.py | 5 +- custom/managers/__init__.py | 3 - custom/managers/chat.py | 42 ------ custom/managers/chunks.py | 97 ------------ custom/managers/data.py | 32 ---- custom/networking/__init__.py | 0 custom/networking/packets/__init__.py | 0 .../packets/clientbound/__init__.py | 0 .../packets/clientbound/play/__init__.py | 0 .../clientbound/play/block_change_packet.py | 112 -------------- custom/networking/types/__init__.py | 0 custom/networking/types/basic.py | 12 -- monkey_patch.py | 12 +- {custom => protocol}/__init__.py | 0 protocol/managers.py | 140 ++++++++++++++++++ .../play/chunk_data.py => protocol/packets.py | 115 +++++++++++++- .../types/nbt.py => protocol/types.py | 23 +-- 17 files changed, 275 insertions(+), 318 deletions(-) delete mode 100644 custom/managers/__init__.py delete mode 100644 custom/managers/chat.py delete mode 100644 custom/managers/chunks.py delete mode 100644 custom/managers/data.py delete mode 100644 custom/networking/__init__.py delete mode 100644 custom/networking/packets/__init__.py delete mode 100644 custom/networking/packets/clientbound/__init__.py delete mode 100644 custom/networking/packets/clientbound/play/__init__.py delete mode 100644 custom/networking/packets/clientbound/play/block_change_packet.py delete mode 100644 custom/networking/types/__init__.py delete mode 100644 custom/networking/types/basic.py rename {custom => protocol}/__init__.py (100%) create mode 100644 protocol/managers.py rename custom/networking/packets/clientbound/play/chunk_data.py => protocol/packets.py (50%) rename custom/networking/types/nbt.py => protocol/types.py (86%) diff --git a/bot.py b/bot.py index cbe72dc..b01e796 100644 --- a/bot.py +++ b/bot.py @@ -13,15 +13,14 @@ SERVER = os.environ['SERVER'] import monkey_patch # must be before any possible pyCraft imports -from custom.managers import DataManager, ChunksManager, ChatManager -from custom.managers.chunks import ChunkNotLoadedException from minecraft import authentication from minecraft.exceptions import YggdrasilError from minecraft.networking.connection import Connection from minecraft.networking.packets import Packet, clientbound, serverbound -from custom.networking.packets.clientbound.play.block_change_packet import BlockChangePacket +from protocol.managers import DataManager, ChunksManager, ChatManager, ChunkNotLoadedException +from protocol.packets import BlockChangePacket from bunch import Bunch from panda3d.core import LPoint3f, LVector3f diff --git a/custom/managers/__init__.py b/custom/managers/__init__.py deleted file mode 100644 index b7e64e5..0000000 --- a/custom/managers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .data import DataManager -from .chunks import ChunksManager -from .chat import ChatManager diff --git a/custom/managers/chat.py b/custom/managers/chat.py deleted file mode 100644 index fe2dc61..0000000 --- a/custom/managers/chat.py +++ /dev/null @@ -1,42 +0,0 @@ -import json - -from minecraft.networking.packets import clientbound, serverbound - -class ChatManager: - def __init__(self, global_state): - self.g = global_state - self.handler = None - - self.g.connection.register_packet_listener(self.print_chat, clientbound.play.ChatMessagePacket) - - def translate_chat(self, data): - if isinstance(data, str): - return data - elif 'extra' in data: - return ''.join([self.translate_chat(x) for x in data['extra']]) - elif 'text' in data: - return data['text'] - else: - return '?' - - def print_chat(self, chat_packet): - # TODO: Replace with handler - try: - source = chat_packet.field_string('position') - text = self.translate_chat(json.loads(chat_packet.json_data)) - print('[%s] %s'%(source, text)) - if self.handler: - self.handler((source, text)) - except Exception as ex: - print('Exception %r on message (%s): %s' % (ex, chat_packet.field_string('position'), chat_packet.json_data)) - - def set_handler(self, func): - self.handler = func - - def send(self, text): - if not text: - # Prevents connection bug when sending empty chat message - return - packet = serverbound.play.ChatPacket() - packet.message = text - self.g.connection.write_packet(packet) diff --git a/custom/managers/chunks.py b/custom/managers/chunks.py deleted file mode 100644 index 44fb88d..0000000 --- a/custom/managers/chunks.py +++ /dev/null @@ -1,97 +0,0 @@ -from math import floor - -from ..networking.packets.clientbound.play import block_change_packet, chunk_data - -class ChunksManager: - - def __init__(self, data_manager): - self.data = data_manager - self.chunks = {} - self.biomes = {} - - def handle_block(self, block_packet): - self.set_block_at(block_packet.location.x, block_packet.location.y, block_packet.location.z, block_packet.block_state_id) - #self.print_chunk(self.get_chunk(floor(block_packet.location.x/16), floor(block_packet.location.y/16), floor(block_packet.location.z/16)), block_packet.location.y%16) - #print('Block %s at %s'%(blocks_states[block_packet.block_state_id], block_packet.location)) - - def handle_multiblock(self, multiblock_packet): - for b in multiblock_packet.records: - self.handle_block(b) - - def handle_chunk(self, chunk_packet): - for i in chunk_packet.chunks: - self.chunks[(chunk_packet.x, i, chunk_packet.z)] = chunk_packet.chunks[i] - self.biomes[(chunk_packet.x, None, chunk_packet.z)] = chunk_packet.biomes # FIXME - - def register(self, connection): - connection.register_packet_listener(self.handle_block, block_change_packet.BlockChangePacket) - connection.register_packet_listener(self.handle_multiblock, block_change_packet.MultiBlockChangePacket) - connection.register_packet_listener(self.handle_chunk, chunk_data.ChunkDataPacket) - - def get_chunk(self, x, y, z): - index = (x, y, z) - if not index in self.chunks: - raise ChunkNotLoadedException(index) - return self.chunks[index] - - def get_loaded_area(self, ignore_empty=False): - first = next(iter(self.chunks.keys())) - x0 = x1 = first[0] - y0 = y1 = first[1] - z0 = z1 = first[2] - for k in self.chunks.keys(): - if ignore_empty and self.chunks[k].empty: - continue - x0 = min(x0, k[0]) - x1 = max(x1, k[0]) - y0 = min(y0, k[1]) - y1 = max(y1, k[1]) - z0 = min(z0, k[2]) - z1 = max(z1, k[2]) - return ((x0,y0,z0),(x1,y1,z1)) - - def get_block_at(self, x, y, z): - c = self.get_chunk(floor(x/16), floor(y/16), floor(z/16)) - return c.get_block_at(x%16, y%16, z%16) - - def set_block_at(self, x, y, z, block): - c = self.get_chunk(floor(x/16), floor(y/16), floor(z/16)) - c.set_block_at(x%16, y%16, z%16, block) - - def print_chunk(self, chunk, y_slice): - print("This is chunk %d %d %d at slice %d:"%(chunk.x, chunk.y, chunk.z, y_slice)) - print("+%s+"%("-"*16)) - for z in range(16): - missing = [] - print("|", end="") - for x in range(16): - sid = chunk.get_block_at(x, y_slice, z) - bloc = self.data.blocks_states[sid] - if bloc == "minecraft:air" or bloc == "minecraft:cave_air": - c = " " - elif bloc == "minecraft:grass_block" or bloc == "minecraft:dirt": - c = "-" - elif bloc == "minecraft:water": - c = "~" - elif bloc == "minecraft:lava": - c = "!" - elif bloc == "minecraft:bedrock": - c = "_" - elif bloc == "minecraft:stone": - c = "X" - else: - missing.append(bloc) - c = "?" - - print(c, end="") - print("| %s"%(",".join(missing))) - print("+%s+"%("-"*16)) - if chunk.entities: - print("Entities in slice: %s"%(", ".join([x['id'].decode() for x in chunk.entities]))) - - -class ChunkNotLoadedException(Exception): - def __str__(self): - pos = self.args[0] - return "Chunk at %d %d %d not loaded (yet?)"%(pos[0], pos[1], pos[2]) - diff --git a/custom/managers/data.py b/custom/managers/data.py deleted file mode 100644 index 16028d8..0000000 --- a/custom/managers/data.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -import json - -class DataManager: - - def __init__(self, directory): - self.blocks = {} - self.blocks_states = {} - self.blocks_properties = {} - self.registries = {} - self.biomes = {} - self.entity_type = {} - - if not os.path.isdir(directory): - raise FileNotFoundError("%s is not a valid directory") - - if not os.path.isfile("%s/registries.json"%(directory)): - raise FileNotFoundError("%s is not a valid minecraft data directory") - - with open("%s/blocks.json"%(directory)) as f: - blocks = json.loads(f.read()) - for x in blocks: - for s in blocks[x]['states']: - self.blocks_states[s['id']] = x - self.blocks_properties[s['id']] = s.get('properties', {}) - - with open("%s/registries.json"%(directory)) as f: - registries = json.loads(f.read()) - #for x in registries["minecraft:biome"]["entries"]: - # self.biomes[registries["minecraft:biome"]["entries"][x]["protocol_id"]] = x - for x in registries["minecraft:entity_type"]["entries"]: - self.entity_type[registries["minecraft:entity_type"]["entries"][x]["protocol_id"]] = x diff --git a/custom/networking/__init__.py b/custom/networking/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/custom/networking/packets/__init__.py b/custom/networking/packets/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/custom/networking/packets/clientbound/__init__.py b/custom/networking/packets/clientbound/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/custom/networking/packets/clientbound/play/__init__.py b/custom/networking/packets/clientbound/play/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/custom/networking/packets/clientbound/play/block_change_packet.py b/custom/networking/packets/clientbound/play/block_change_packet.py deleted file mode 100644 index baea571..0000000 --- a/custom/networking/packets/clientbound/play/block_change_packet.py +++ /dev/null @@ -1,112 +0,0 @@ -from minecraft.networking.packets import Packet -from minecraft.networking.types import ( - VarInt, Integer, UnsignedByte, Position, Vector, MutableRecord, - attribute_alias, multi_attribute_alias, Long, Boolean, VarLong, -) - - -class BlockChangePacket(Packet): - id = 0x0B - 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): - id = 0x3B - 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): - data = VarLong.read(file_object) - self.block_state_id = int(data >> 12) - self.x = int(data >> 8 & 0xf) - self.z = int(data >> 4 & 0xf) - self.y = int(data & 0xf) - # 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): - raise - 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): - coords = Long.read(file_object) - self.chunk_x = int(coords >> 42 & 0x3fffff) - self.chunk_z = int(coords >> 20 & 0x3fffff) - self.chunk_y = int(coords & 0xfffff) - self.unknown = Boolean.read(file_object) - array_size = VarInt.read(file_object) - self.records = [] - for i in range(array_size): - record = self.Record() - record.read(file_object, self) - self.records.append(record) - - def write_fields(self, packet_buffer): - raise - 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) diff --git a/custom/networking/types/__init__.py b/custom/networking/types/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/custom/networking/types/basic.py b/custom/networking/types/basic.py deleted file mode 100644 index 64c35f6..0000000 --- a/custom/networking/types/basic.py +++ /dev/null @@ -1,12 +0,0 @@ -from minecraft.networking.types.basic import Type, Byte, Short, Integer, Long, Float, Double, ShortPrefixedByteArray - -class IntegerPrefixedByteArray(Type): - @staticmethod - def read(file_object): - length = Integer.read(file_object) - return struct.unpack(str(length) + "s", file_object.read(length))[0] - - @staticmethod - def send(value, socket): - Integer.send(len(value), socket) - socket.send(value) diff --git a/monkey_patch.py b/monkey_patch.py index 9ce2f28..378b4b2 100644 --- a/monkey_patch.py +++ b/monkey_patch.py @@ -1,17 +1,17 @@ import minecraft.networking.packets -from custom.networking.packets.clientbound.play import chunk_data, block_change_packet +from protocol import packets def get_packets(old_get_packets): def wrapper(func, context): print('Monkey-patch worked.') - packets = func(context) + mc_packets = func(context) # add any custom packets here - packets.add(chunk_data.ChunkDataPacket) - packets.add(block_change_packet.BlockChangePacket) - packets.add(block_change_packet.MultiBlockChangePacket) + mc_packets.add(packets.ChunkDataPacket) + mc_packets.add(packets.BlockChangePacket) + mc_packets.add(packets.MultiBlockChangePacket) - return packets + return mc_packets return lambda x: wrapper(old_get_packets, x) minecraft.networking.packets.clientbound.play.get_packets = get_packets(minecraft.networking.packets.clientbound.play.get_packets) diff --git a/custom/__init__.py b/protocol/__init__.py similarity index 100% rename from custom/__init__.py rename to protocol/__init__.py diff --git a/protocol/managers.py b/protocol/managers.py new file mode 100644 index 0000000..110b059 --- /dev/null +++ b/protocol/managers.py @@ -0,0 +1,140 @@ +import os +from math import floor +import json + +from minecraft.networking.packets import clientbound, serverbound +from protocol import packets + +class DataManager: + def __init__(self, directory): + self.blocks = {} + self.blocks_states = {} + self.blocks_properties = {} + self.registries = {} + self.biomes = {} + self.entity_type = {} + + if not os.path.isdir(directory): + raise FileNotFoundError("%s is not a valid directory") + + if not os.path.isfile("%s/registries.json"%(directory)): + raise FileNotFoundError("%s is not a valid minecraft data directory") + + with open("%s/blocks.json"%(directory)) as f: + blocks = json.loads(f.read()) + for x in blocks: + for s in blocks[x]['states']: + self.blocks_states[s['id']] = x + self.blocks_properties[s['id']] = s.get('properties', {}) + + with open("%s/registries.json"%(directory)) as f: + registries = json.loads(f.read()) + #for x in registries["minecraft:biome"]["entries"]: + # self.biomes[registries["minecraft:biome"]["entries"][x]["protocol_id"]] = x + for x in registries["minecraft:entity_type"]["entries"]: + self.entity_type[registries["minecraft:entity_type"]["entries"][x]["protocol_id"]] = x + + +class ChunksManager: + def __init__(self, data_manager): + self.data = data_manager + self.chunks = {} + self.biomes = {} + + def handle_block(self, block_packet): + self.set_block_at(block_packet.location.x, block_packet.location.y, block_packet.location.z, block_packet.block_state_id) + #self.print_chunk(self.get_chunk(floor(block_packet.location.x/16), floor(block_packet.location.y/16), floor(block_packet.location.z/16)), block_packet.location.y%16) + #print('Block %s at %s'%(blocks_states[block_packet.block_state_id], block_packet.location)) + + def handle_multiblock(self, multiblock_packet): + for b in multiblock_packet.records: + self.handle_block(b) + + def handle_chunk(self, chunk_packet): + for i in chunk_packet.chunks: + self.chunks[(chunk_packet.x, i, chunk_packet.z)] = chunk_packet.chunks[i] + self.biomes[(chunk_packet.x, None, chunk_packet.z)] = chunk_packet.biomes # FIXME + + def register(self, connection): + connection.register_packet_listener(self.handle_block, packets.BlockChangePacket) + connection.register_packet_listener(self.handle_multiblock, packets.MultiBlockChangePacket) + connection.register_packet_listener(self.handle_chunk, packets.ChunkDataPacket) + + def get_chunk(self, x, y, z): + index = (x, y, z) + if not index in self.chunks: + raise ChunkNotLoadedException(index) + return self.chunks[index] + + def get_loaded_area(self, ignore_empty=False): + first = next(iter(self.chunks.keys())) + x0 = x1 = first[0] + y0 = y1 = first[1] + z0 = z1 = first[2] + for k in self.chunks.keys(): + if ignore_empty and self.chunks[k].empty: + continue + x0 = min(x0, k[0]) + x1 = max(x1, k[0]) + y0 = min(y0, k[1]) + y1 = max(y1, k[1]) + z0 = min(z0, k[2]) + z1 = max(z1, k[2]) + return ((x0,y0,z0),(x1,y1,z1)) + + def get_block_at(self, x, y, z): + c = self.get_chunk(floor(x/16), floor(y/16), floor(z/16)) + return c.get_block_at(x%16, y%16, z%16) + + def set_block_at(self, x, y, z, block): + c = self.get_chunk(floor(x/16), floor(y/16), floor(z/16)) + c.set_block_at(x%16, y%16, z%16, block) + + +class ChunkNotLoadedException(Exception): + def __str__(self): + pos = self.args[0] + return "Chunk at %d %d %d not loaded (yet?)"%(pos[0], pos[1], pos[2]) + + +class ChatManager: + def __init__(self, global_state): + self.g = global_state + self.handler = None + + self.g.connection.register_packet_listener(self.print_chat, clientbound.play.ChatMessagePacket) + + def translate_chat(self, data): + if isinstance(data, str): + return data + elif 'extra' in data: + return ''.join([self.translate_chat(x) for x in data['extra']]) + elif 'text' in data: + return data['text'] + elif 'translate' in data: + return data['translate'] + else: + print(data) + return '?' + + def print_chat(self, chat_packet): + try: + source = chat_packet.field_string('position') + text = self.translate_chat(json.loads(chat_packet.json_data)) + print('[%s] %s'%(source, text)) + except Exception as ex: + print('Exception %r on message (%s): %s' % (ex, chat_packet.field_string('position'), chat_packet.json_data)) + + if self.handler: + self.handler((source, text)) + + def set_handler(self, func): + self.handler = func + + def send(self, text): + if not text: + # Prevents connection bug when sending empty chat message + return + packet = serverbound.play.ChatPacket() + packet.message = text + self.g.connection.write_packet(packet) diff --git a/custom/networking/packets/clientbound/play/chunk_data.py b/protocol/packets.py similarity index 50% rename from custom/networking/packets/clientbound/play/chunk_data.py rename to protocol/packets.py index 9e2e9b7..9c25aa9 100644 --- a/custom/networking/packets/clientbound/play/chunk_data.py +++ b/protocol/packets.py @@ -6,7 +6,120 @@ from minecraft.networking.types import ( multi_attribute_alias, Vector, UnsignedLong ) -from ....types.nbt import Nbt +from protocol.types import Nbt +from minecraft.networking.packets import Packet +from minecraft.networking.types import ( + VarInt, Integer, UnsignedByte, Position, Vector, MutableRecord, + attribute_alias, multi_attribute_alias, Long, Boolean, VarLong, +) + + +class BlockChangePacket(Packet): + id = 0x0B + 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): + id = 0x3B + 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): + data = VarLong.read(file_object) + self.block_state_id = int(data >> 12) + self.x = int(data >> 8 & 0xf) + self.z = int(data >> 4 & 0xf) + self.y = int(data & 0xf) + # 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): + raise + 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): + coords = Long.read(file_object) + self.chunk_x = int(coords >> 42 & 0x3fffff) + self.chunk_z = int(coords >> 20 & 0x3fffff) + self.chunk_y = int(coords & 0xfffff) + self.unknown = Boolean.read(file_object) + array_size = VarInt.read(file_object) + self.records = [] + for i in range(array_size): + record = self.Record() + record.read(file_object, self) + self.records.append(record) + + def write_fields(self, packet_buffer): + raise + 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) + class ChunkDataPacket(Packet): id = 0x20 diff --git a/custom/networking/types/nbt.py b/protocol/types.py similarity index 86% rename from custom/networking/types/nbt.py rename to protocol/types.py index b6f2ffc..c136ea2 100644 --- a/custom/networking/types/nbt.py +++ b/protocol/types.py @@ -1,16 +1,23 @@ -"""Contains definition for minecraft's NBT format. -""" from __future__ import division + +from minecraft.networking.types.basic import Type, Byte, Short, Integer, Long, Float, Double, ShortPrefixedByteArray + import struct from minecraft.networking.types.utility import Vector from minecraft.networking.types.basic import Type, Byte, Short, Integer, Long, Float, Double, ShortPrefixedByteArray -from .basic import IntegerPrefixedByteArray -__all__ = ( - 'Nbt', -) +class IntegerPrefixedByteArray(Type): + @staticmethod + def read(file_object): + length = Integer.read(file_object) + return struct.unpack(str(length) + "s", file_object.read(length))[0] + + @staticmethod + def send(value, socket): + Integer.send(len(value), socket) + socket.send(value) TAG_End = 0 TAG_Byte = 1 @@ -26,9 +33,7 @@ TAG_Compound = 10 TAG_Int_Array = 11 TAG_Long_Array = 12 - class Nbt(Type): - @staticmethod def read(file_object): type_id = Byte.read(file_object) @@ -91,5 +96,3 @@ class Nbt(Type): def send(value, socket): # TODO pass - -