diff --git a/minecraft/networking/packets.py b/minecraft/networking/packets.py index 4557dd8..f03888f 100644 --- a/minecraft/networking/packets.py +++ b/minecraft/networking/packets.py @@ -3,7 +3,7 @@ from zlib import compress from .types import ( VarInt, Integer, Float, Double, UnsignedShort, Long, Byte, UnsignedByte, - String, VarIntPrefixedByteArray, Boolean, UUID, Short + String, VarIntPrefixedByteArray, Boolean, UUID, Short, UnsignedLong, Position ) @@ -1007,6 +1007,26 @@ class ClientSpawnObject(Packet): def write(self, socket, compression_threshold=None): raise NotImplementedError +class ClientBlockChange(Packet): + @staticmethod + def get_id(context): + return 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' + + def read(self, file_object): + self.location = Position.read(file_object) + blockData = VarInt.read(file_object) + self.blockId = (blockData >> 4) + self.blockMeta = (blockData & 0xF) + + def write(self, socket, compression_threshold=None): + raise NotImplementedError + def state_playing_clientbound(context): packets = { KeepAlivePacketClientbound, @@ -1022,6 +1042,7 @@ def state_playing_clientbound(context): ClientCombatEvent, ClientExplosion, ClientSpawnObject, + ClientBlockChange, } if context.protocol_version <= 47: packets |= { diff --git a/minecraft/networking/types.py b/minecraft/networking/types.py index abc83a6..2146733 100644 --- a/minecraft/networking/types.py +++ b/minecraft/networking/types.py @@ -147,6 +147,14 @@ class Long(Type): def send(value, socket): socket.send(struct.pack('>q', value)) +class UnsignedLong(Type): + @staticmethod + def read(file_object): + return struct.unpack('>Q', file_object.read(8))[0] + + @staticmethod + def send(value, socket): + socket.send(struct.pack('>Q', value)) class Float(Type): @staticmethod @@ -213,3 +221,31 @@ class UUID(Type): @staticmethod def send(value, socket): socket.send(uuid.UUID(value).bytes) + +class Position(Type): + @staticmethod + def read(file_object): + location = UnsignedLong.read(file_object) # 64-bit value + x = int(location >> 38) # 26 MSBs + y = int((location >> 26) & 0xFFF) # 12 bits between them + z = int(location & 0x3FFFFFF) # 26 LSBs + + if x >= pow(2,25): + x -= pow(2,26) + + if y >= pow(2,11): + y -= pow(2,12) + + if z >= pow(2,25): + z -= pow(2,26) + + return {'x': x, 'y': y, 'z': z} + + @staticmethod + def send(value, socket): + # Position is a single encoded long value; use encode method to encode position properly + UnsignedLong.send(value, socket) + + @staticmethod + def encode(x,y,z): + return ((x & 0x3FFFFFF) << 38) | ((y & 0xFFF) << 26) | (z & 0x3FFFFFF)