mirror of
https://github.com/ammaraskar/pyCraft.git
synced 2024-12-22 16:48:33 +01:00
Add support for Minecraft 18w43a to 1.14 (protocols 441 to 477)
This commit introduces two backward-incompatible changes which may break existing code: (1) `networking.packets.clientbound.play.SpawnObjectPacket.EntityType' is no longer accessible as an attribute of the the `SpawnObjectPacket' class: the values now depend on a `ConnectionContext`, and must be accessed through an instance, or using `SpawnObjectPacket.field_enum'. See the text of the `AttributeError` raised from the descriptor for `SpawnObjectPacket.EntityType` for the full details. (2) For some subclasses of `networking.types.Type', it is necessary to call the methods `read_with_context' and `send_with_context' instead of `read' and `send', supplying a `ConnectionContext' for those data types - currently only `Position` - whose layout depends on it.
This commit is contained in:
parent
9b43d6f004
commit
612fa8e324
@ -29,6 +29,7 @@ pyCraft is compatible with the following Minecraft releases:
|
||||
* 1.11, 1.11.1, 1.11.2
|
||||
* 1.12, 1.12.1, 1.12.2
|
||||
* 1.13, 1.13.1, 1.13.2
|
||||
* 1.14
|
||||
|
||||
In addition, some development snapshots and pre-release versions are supported:
|
||||
`<minecraft/__init__.py>`_ contains a full list of supported Minecraft versions
|
||||
|
@ -6,132 +6,170 @@ with a MineCraft server.
|
||||
__version__ = "0.5.0"
|
||||
|
||||
SUPPORTED_MINECRAFT_VERSIONS = {
|
||||
'1.8': 47,
|
||||
'1.8.1': 47,
|
||||
'1.8.2': 47,
|
||||
'1.8.3': 47,
|
||||
'1.8.4': 47,
|
||||
'1.8.5': 47,
|
||||
'1.8.6': 47,
|
||||
'1.8.7': 47,
|
||||
'1.8.8': 47,
|
||||
'1.8.9': 47,
|
||||
'1.9': 107,
|
||||
'1.9.1': 108,
|
||||
'1.9.2': 109,
|
||||
'1.9.3': 110,
|
||||
'1.9.4': 110,
|
||||
'1.10': 210,
|
||||
'1.10.1': 210,
|
||||
'1.10.2': 210,
|
||||
'16w32a': 301,
|
||||
'16w32b': 302,
|
||||
'16w33a': 303,
|
||||
'16w35a': 304,
|
||||
'16w36a': 305,
|
||||
'16w38a': 306,
|
||||
'16w39a': 307,
|
||||
'16w39b': 308,
|
||||
'16w39c': 309,
|
||||
'16w40a': 310,
|
||||
'16w41a': 311,
|
||||
'16w42a': 312,
|
||||
'16w43a': 313,
|
||||
'16w44a': 313,
|
||||
'1.11-pre1': 314,
|
||||
'1.11': 315,
|
||||
'16w50a': 316,
|
||||
'1.11.1': 316,
|
||||
'1.11.2': 316,
|
||||
'17w06a': 317,
|
||||
'17w13a': 318,
|
||||
'17w13b': 319,
|
||||
'17w14a': 320,
|
||||
'17w15a': 321,
|
||||
'17w16a': 322,
|
||||
'17w16b': 323,
|
||||
'17w17a': 324,
|
||||
'17w17b': 325,
|
||||
'17w18a': 326,
|
||||
'17w18b': 327,
|
||||
'1.12-pre1': 328,
|
||||
'1.12-pre2': 329,
|
||||
'1.12-pre3': 330,
|
||||
'1.12-pre4': 331,
|
||||
'1.12-pre5': 332,
|
||||
'1.12-pre6': 333,
|
||||
'1.12-pre7': 334,
|
||||
'1.12': 335,
|
||||
'17w31a': 336,
|
||||
'1.12.1-pre1': 337,
|
||||
'1.12.1': 338,
|
||||
'1.12.2-pre1': 339,
|
||||
'1.12.2-pre2': 339,
|
||||
'1.12.2': 340,
|
||||
'17w43a': 341,
|
||||
'17w43b': 342,
|
||||
'17w45a': 343,
|
||||
'17w45b': 344,
|
||||
'17w46a': 345,
|
||||
'17w47a': 346,
|
||||
'17w47b': 347,
|
||||
'17w48a': 348,
|
||||
'17w49a': 349,
|
||||
'17w49b': 350,
|
||||
'17w50a': 351,
|
||||
'18w01a': 352,
|
||||
'18w02a': 353,
|
||||
'18w03a': 354,
|
||||
'18w03b': 355,
|
||||
'18w05a': 356,
|
||||
'18w06a': 357,
|
||||
'18w07a': 358,
|
||||
'18w07b': 359,
|
||||
'18w07c': 360,
|
||||
'18w08a': 361,
|
||||
'18w08b': 362,
|
||||
'18w09a': 363,
|
||||
'18w10a': 364,
|
||||
'18w10b': 365,
|
||||
'18w10c': 366,
|
||||
'18w10d': 367,
|
||||
'18w11a': 368,
|
||||
'18w14a': 369,
|
||||
'18w14b': 370,
|
||||
'18w15a': 371,
|
||||
'18w16a': 372,
|
||||
'18w19a': 373,
|
||||
'18w19b': 374,
|
||||
'18w20a': 375,
|
||||
'18w20b': 376,
|
||||
'18w20c': 377,
|
||||
'18w21a': 378,
|
||||
'18w21b': 379,
|
||||
'18w22a': 380,
|
||||
'18w22b': 381,
|
||||
'18w22c': 382,
|
||||
'1.13-pre1': 383,
|
||||
'1.13-pre2': 384,
|
||||
'1.13-pre3': 385,
|
||||
'1.13-pre4': 386,
|
||||
'1.13-pre5': 387,
|
||||
'1.13-pre6': 388,
|
||||
'1.13-pre7': 389,
|
||||
'1.13-pre8': 390,
|
||||
'1.13-pre9': 391,
|
||||
'1.13-pre10': 392,
|
||||
'1.13': 393,
|
||||
'18w30a': 394,
|
||||
'18w30b': 395,
|
||||
'18w31a': 396,
|
||||
'18w32a': 397,
|
||||
'18w33a': 398,
|
||||
'1.13.1-pre1': 399,
|
||||
'1.13.1-pre2': 400,
|
||||
'1.13.1': 401,
|
||||
'1.13.2-pre1': 402,
|
||||
'1.13.2-pre2': 403,
|
||||
'1.13.2': 404,
|
||||
'1.8': 47,
|
||||
'1.8.1': 47,
|
||||
'1.8.2': 47,
|
||||
'1.8.3': 47,
|
||||
'1.8.4': 47,
|
||||
'1.8.5': 47,
|
||||
'1.8.6': 47,
|
||||
'1.8.7': 47,
|
||||
'1.8.8': 47,
|
||||
'1.8.9': 47,
|
||||
'1.9': 107,
|
||||
'1.9.1': 108,
|
||||
'1.9.2': 109,
|
||||
'1.9.3': 110,
|
||||
'1.9.4': 110,
|
||||
'1.10': 210,
|
||||
'1.10.1': 210,
|
||||
'1.10.2': 210,
|
||||
'16w32a': 301,
|
||||
'16w32b': 302,
|
||||
'16w33a': 303,
|
||||
'16w35a': 304,
|
||||
'16w36a': 305,
|
||||
'16w38a': 306,
|
||||
'16w39a': 307,
|
||||
'16w39b': 308,
|
||||
'16w39c': 309,
|
||||
'16w40a': 310,
|
||||
'16w41a': 311,
|
||||
'16w42a': 312,
|
||||
'16w43a': 313,
|
||||
'16w44a': 313,
|
||||
'1.11-pre1': 314,
|
||||
'1.11': 315,
|
||||
'16w50a': 316,
|
||||
'1.11.1': 316,
|
||||
'1.11.2': 316,
|
||||
'17w06a': 317,
|
||||
'17w13a': 318,
|
||||
'17w13b': 319,
|
||||
'17w14a': 320,
|
||||
'17w15a': 321,
|
||||
'17w16a': 322,
|
||||
'17w16b': 323,
|
||||
'17w17a': 324,
|
||||
'17w17b': 325,
|
||||
'17w18a': 326,
|
||||
'17w18b': 327,
|
||||
'1.12-pre1': 328,
|
||||
'1.12-pre2': 329,
|
||||
'1.12-pre3': 330,
|
||||
'1.12-pre4': 331,
|
||||
'1.12-pre5': 332,
|
||||
'1.12-pre6': 333,
|
||||
'1.12-pre7': 334,
|
||||
'1.12': 335,
|
||||
'17w31a': 336,
|
||||
'1.12.1-pre1': 337,
|
||||
'1.12.1': 338,
|
||||
'1.12.2-pre1': 339,
|
||||
'1.12.2-pre2': 339,
|
||||
'1.12.2': 340,
|
||||
'17w43a': 341,
|
||||
'17w43b': 342,
|
||||
'17w45a': 343,
|
||||
'17w45b': 344,
|
||||
'17w46a': 345,
|
||||
'17w47a': 346,
|
||||
'17w47b': 347,
|
||||
'17w48a': 348,
|
||||
'17w49a': 349,
|
||||
'17w49b': 350,
|
||||
'17w50a': 351,
|
||||
'18w01a': 352,
|
||||
'18w02a': 353,
|
||||
'18w03a': 354,
|
||||
'18w03b': 355,
|
||||
'18w05a': 356,
|
||||
'18w06a': 357,
|
||||
'18w07a': 358,
|
||||
'18w07b': 359,
|
||||
'18w07c': 360,
|
||||
'18w08a': 361,
|
||||
'18w08b': 362,
|
||||
'18w09a': 363,
|
||||
'18w10a': 364,
|
||||
'18w10b': 365,
|
||||
'18w10c': 366,
|
||||
'18w10d': 367,
|
||||
'18w11a': 368,
|
||||
'18w14a': 369,
|
||||
'18w14b': 370,
|
||||
'18w15a': 371,
|
||||
'18w16a': 372,
|
||||
'18w19a': 373,
|
||||
'18w19b': 374,
|
||||
'18w20a': 375,
|
||||
'18w20b': 376,
|
||||
'18w20c': 377,
|
||||
'18w21a': 378,
|
||||
'18w21b': 379,
|
||||
'18w22a': 380,
|
||||
'18w22b': 381,
|
||||
'18w22c': 382,
|
||||
'1.13-pre1': 383,
|
||||
'1.13-pre2': 384,
|
||||
'1.13-pre3': 385,
|
||||
'1.13-pre4': 386,
|
||||
'1.13-pre5': 387,
|
||||
'1.13-pre6': 388,
|
||||
'1.13-pre7': 389,
|
||||
'1.13-pre8': 390,
|
||||
'1.13-pre9': 391,
|
||||
'1.13-pre10': 392,
|
||||
'1.13': 393,
|
||||
'18w30a': 394,
|
||||
'18w30b': 395,
|
||||
'18w31a': 396,
|
||||
'18w32a': 397,
|
||||
'18w33a': 398,
|
||||
'1.13.1-pre1': 399,
|
||||
'1.13.1-pre2': 400,
|
||||
'1.13.1': 401,
|
||||
'1.13.2-pre1': 402,
|
||||
'1.13.2-pre2': 403,
|
||||
'1.13.2': 404,
|
||||
'18w43a': 441,
|
||||
'18w43b': 441,
|
||||
'18w43c': 442,
|
||||
'18w44a': 443,
|
||||
'18w45a': 444,
|
||||
'18w46a': 445,
|
||||
'18w47a': 446,
|
||||
'18w47b': 447,
|
||||
'18w48a': 448,
|
||||
'18w48b': 449,
|
||||
'18w49a': 450,
|
||||
'18w50a': 451,
|
||||
'19w02a': 452,
|
||||
'19w03a': 453,
|
||||
'19w03b': 454,
|
||||
'19w03c': 455,
|
||||
'19w04a': 456,
|
||||
'19w04b': 457,
|
||||
'19w05a': 458,
|
||||
'19w06a': 459,
|
||||
'19w07a': 460,
|
||||
'19w08a': 461,
|
||||
'19w08b': 462,
|
||||
'19w09a': 463,
|
||||
'19w11a': 464,
|
||||
'19w11b': 465,
|
||||
'19w12a': 466,
|
||||
'19w12b': 467,
|
||||
'19w13a': 468,
|
||||
'19w13b': 469,
|
||||
'19w14a': 470,
|
||||
'19w14b': 471,
|
||||
'1.14 Pre-Release 1': 472,
|
||||
'1.14 Pre-Release 2': 473,
|
||||
'1.14 Pre-Release 3': 474,
|
||||
'1.14 Pre-Release 4': 475,
|
||||
'1.14 Pre-Release 5': 476,
|
||||
'1.14': 477,
|
||||
}
|
||||
|
||||
SUPPORTED_PROTOCOL_VERSIONS = \
|
||||
|
@ -47,7 +47,8 @@ def get_packets(context):
|
||||
class KeepAlivePacket(AbstractKeepAlivePacket):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x21 if context.protocol_version >= 389 else \
|
||||
return 0x20 if context.protocol_version >= 471 else \
|
||||
0x21 if context.protocol_version >= 389 else \
|
||||
0x20 if context.protocol_version >= 345 else \
|
||||
0x1F if context.protocol_version >= 332 else \
|
||||
0x20 if context.protocol_version >= 318 else \
|
||||
@ -70,9 +71,10 @@ class JoinGamePacket(Packet):
|
||||
{'entity_id': Integer},
|
||||
{'game_mode': UnsignedByte},
|
||||
{'dimension': Integer if context.protocol_version >= 108 else Byte},
|
||||
{'difficulty': UnsignedByte},
|
||||
{'difficulty': UnsignedByte} if context.protocol_version < 464 else {},
|
||||
{'max_players': UnsignedByte},
|
||||
{'level_type': String},
|
||||
{'render_distance': VarInt} if context.protocol_version >= 468 else {},
|
||||
{'reduced_debug_info': Boolean}])
|
||||
|
||||
|
||||
@ -99,7 +101,8 @@ class ChatMessagePacket(Packet):
|
||||
class DisconnectPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x1B if context.protocol_version >= 345 else \
|
||||
return 0x1A if context.protocol_version >= 471 else \
|
||||
0x1B if context.protocol_version >= 345 else \
|
||||
0x1A if context.protocol_version >= 332 else \
|
||||
0x1B if context.protocol_version >= 318 else \
|
||||
0x1A if context.protocol_version >= 107 else \
|
||||
@ -145,7 +148,10 @@ class SpawnPlayerPacket(Packet):
|
||||
class EntityVelocityPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x41 if context.protocol_version >= 389 else \
|
||||
return 0x45 if context.protocol_version >= 471 else \
|
||||
0x41 if context.protocol_version >= 461 else \
|
||||
0x42 if context.protocol_version >= 451 else \
|
||||
0x41 if context.protocol_version >= 389 else \
|
||||
0x40 if context.protocol_version >= 352 else \
|
||||
0x3F if context.protocol_version >= 345 else \
|
||||
0x3E if context.protocol_version >= 336 else \
|
||||
@ -167,7 +173,10 @@ class EntityVelocityPacket(Packet):
|
||||
class UpdateHealthPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x44 if context.protocol_version >= 389 else \
|
||||
return 0x48 if context.protocol_version >= 471 else \
|
||||
0x44 if context.protocol_version >= 461 else \
|
||||
0x45 if context.protocol_version >= 451 else \
|
||||
0x44 if context.protocol_version >= 389 else \
|
||||
0x43 if context.protocol_version >= 352 else \
|
||||
0x42 if context.protocol_version >= 345 else \
|
||||
0x41 if context.protocol_version >= 336 else \
|
||||
@ -188,7 +197,8 @@ class UpdateHealthPacket(Packet):
|
||||
class PluginMessagePacket(AbstractPluginMessagePacket):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x19 if context.protocol_version >= 345 else \
|
||||
return 0x18 if context.protocol_version >= 471 else \
|
||||
0x19 if context.protocol_version >= 345 else \
|
||||
0x18 if context.protocol_version >= 332 else \
|
||||
0x19 if context.protocol_version >= 318 else \
|
||||
0x18 if context.protocol_version >= 70 else \
|
||||
@ -198,7 +208,11 @@ class PluginMessagePacket(AbstractPluginMessagePacket):
|
||||
class PlayerListHeaderAndFooterPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x4E if context.protocol_version >= 393 else \
|
||||
return 0x53 if context.protocol_version >= 471 else \
|
||||
0x5F if context.protocol_version >= 461 else \
|
||||
0x50 if context.protocol_version >= 451 else \
|
||||
0x4F if context.protocol_version >= 441 else \
|
||||
0x4E if context.protocol_version >= 393 else \
|
||||
0x4A if context.protocol_version >= 338 else \
|
||||
0x49 if context.protocol_version >= 335 else \
|
||||
0x47 if context.protocol_version >= 110 else \
|
||||
|
@ -8,7 +8,9 @@ from minecraft.networking.types import (
|
||||
class CombatEventPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x2F if context.protocol_version >= 389 else \
|
||||
return 0x32 if context.protocol_version >= 471 else \
|
||||
0x30 if context.protocol_version >= 451 else \
|
||||
0x2F if context.protocol_version >= 389 else \
|
||||
0x2E if context.protocol_version >= 345 else \
|
||||
0x2D if context.protocol_version >= 336 else \
|
||||
0x2C if context.protocol_version >= 332 else \
|
||||
|
@ -5,7 +5,8 @@ from minecraft.networking.packets import Packet
|
||||
class ExplosionPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x1E if context.protocol_version >= 389 else \
|
||||
return 0x1C if context.protocol_version >= 471 else \
|
||||
0x1E if context.protocol_version >= 389 else \
|
||||
0x1D if context.protocol_version >= 345 else \
|
||||
0x1C if context.protocol_version >= 332 else \
|
||||
0x1D if context.protocol_version >= 318 else \
|
||||
|
@ -28,7 +28,7 @@ class MapPacket(Packet):
|
||||
|
||||
class Map(MutableRecord):
|
||||
__slots__ = ('id', 'scale', 'icons', 'pixels', 'width', 'height',
|
||||
'is_tracking_position')
|
||||
'is_tracking_position', 'is_locked')
|
||||
|
||||
def __init__(self, id=None, scale=None, width=128, height=128):
|
||||
self.id = id
|
||||
@ -38,6 +38,7 @@ class MapPacket(Packet):
|
||||
self.height = height
|
||||
self.pixels = bytearray(0 for i in range(width*height))
|
||||
self.is_tracking_position = True
|
||||
self.is_locked = False
|
||||
|
||||
class MapSet(object):
|
||||
__slots__ = 'maps_by_id'
|
||||
@ -58,6 +59,11 @@ class MapPacket(Packet):
|
||||
else:
|
||||
self.is_tracking_position = True
|
||||
|
||||
if self.context.protocol_version >= 452:
|
||||
self.is_locked = Boolean.read(file_object)
|
||||
else:
|
||||
self.is_locked = False
|
||||
|
||||
icon_count = VarInt.read(file_object)
|
||||
self.icons = []
|
||||
for i in range(icon_count):
|
||||
@ -99,6 +105,7 @@ class MapPacket(Packet):
|
||||
z = self.offset[1] + i // self.width
|
||||
map.pixels[x + map.width * z] = self.pixels[i]
|
||||
map.is_tracking_position = self.is_tracking_position
|
||||
map.is_locked = self.is_locked
|
||||
|
||||
def apply_to_map_set(self, map_set):
|
||||
map = map_set.maps_by_id.get(self.map_id)
|
||||
|
@ -8,7 +8,9 @@ from minecraft.networking.types import (
|
||||
class PlayerListItemPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x30 if context.protocol_version >= 389 else \
|
||||
return 0x33 if context.protocol_version >= 471 else \
|
||||
0x31 if context.protocol_version >= 451 else \
|
||||
0x30 if context.protocol_version >= 389 else \
|
||||
0x2F if context.protocol_version >= 345 else \
|
||||
0x2E if context.protocol_version >= 336 else \
|
||||
0x2D if context.protocol_version >= 332 else \
|
||||
|
@ -8,7 +8,9 @@ from minecraft.networking.types import (
|
||||
class PlayerPositionAndLookPacket(Packet, BitFieldEnum):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x32 if context.protocol_version >= 389 else \
|
||||
return 0x35 if context.protocol_version >= 471 else \
|
||||
0x33 if context.protocol_version >= 451 else \
|
||||
0x32 if context.protocol_version >= 389 else \
|
||||
0x31 if context.protocol_version >= 352 else \
|
||||
0x30 if context.protocol_version >= 345 else \
|
||||
0x2F if context.protocol_version >= 336 else \
|
||||
@ -29,7 +31,7 @@ class PlayerPositionAndLookPacket(Packet, BitFieldEnum):
|
||||
])
|
||||
|
||||
field_enum = classmethod(
|
||||
lambda cls, field: cls if field == 'flags' else None)
|
||||
lambda cls, field, context: cls if field == 'flags' else None)
|
||||
|
||||
FLAG_REL_X = 0x01
|
||||
FLAG_REL_Y = 0x02
|
||||
|
@ -1,4 +1,5 @@
|
||||
from minecraft.networking.packets import Packet
|
||||
from minecraft.networking.types.utility import descriptor
|
||||
|
||||
from minecraft.networking.types import (
|
||||
VarInt, UUID, Byte, Double, Integer, UnsignedByte, Short, Enum, Vector,
|
||||
@ -14,40 +15,89 @@ class SpawnObjectPacket(Packet):
|
||||
|
||||
packet_name = 'spawn object'
|
||||
|
||||
class EntityType(Enum):
|
||||
BOAT = 1
|
||||
ITEM_STACK = 2
|
||||
AREA_EFFECT_CLOUD = 3
|
||||
MINECART = 10
|
||||
ACTIVATED_TNT = 50
|
||||
ENDERCRYSTAL = 51
|
||||
ARROW = 60
|
||||
SNOWBALL = 61
|
||||
EGG = 62
|
||||
FIREBALL = 63
|
||||
FIRECHARGE = 64
|
||||
ENDERPERL = 65
|
||||
WITHER_SKULL = 66
|
||||
SHULKER_BULLET = 67
|
||||
LLAMA_SPIT = 68
|
||||
FALLING_OBJECT = 70
|
||||
ITEM_FRAMES = 71
|
||||
EYE_OF_ENDER = 72
|
||||
POTION = 73
|
||||
EXP_BOTTLE = 75
|
||||
FIREWORK_ROCKET = 76
|
||||
LEASH_KNOT = 77
|
||||
ARMORSTAND = 78
|
||||
EVOCATION_FANGS = 79
|
||||
FISHING_HOOK = 90
|
||||
SPECTRAL_ARROW = 91
|
||||
DRAGON_FIREBALL = 93
|
||||
fields = ('entity_id', 'object_uuid', 'type_id',
|
||||
'x', 'y', 'z', 'pitch', 'yaw')
|
||||
|
||||
@descriptor
|
||||
def EntityType(desc, self, cls): # pylint: disable=no-self-argument
|
||||
if self is None:
|
||||
# EntityType is being accessed as a class attribute.
|
||||
raise AttributeError(
|
||||
'This interface is deprecated:\n\n'
|
||||
'As of pyCraft\'s support for Minecraft 1.14, the nested '
|
||||
'class "SpawnObjectPacket.EntityType" cannot be accessed as a '
|
||||
'class attribute, because it depends on the protocol version. '
|
||||
'There are two ways to access the correct version of the '
|
||||
'class:\n\n'
|
||||
'1. Access the "EntityType" attribute of a '
|
||||
'"SpawnObjectPacket" instance with its "context" property '
|
||||
'set.\n\n'
|
||||
'2. Call "SpawnObjectPacket.field_enum(\'type_id\', '
|
||||
'context)".')
|
||||
else:
|
||||
# EntityType is being accessed as an instance attribute.
|
||||
return self.field_enum('type_id', self.context)
|
||||
|
||||
@classmethod
|
||||
def field_enum(cls, field, context):
|
||||
if field != 'type_id' or context is None:
|
||||
return
|
||||
|
||||
pv = context.protocol_version
|
||||
name = 'EntityType_%d' % pv
|
||||
if hasattr(cls, name):
|
||||
return getattr(cls, name)
|
||||
|
||||
class EntityType(Enum):
|
||||
ACTIVATED_TNT = 50 if pv < 458 else 55 # PrimedTnt
|
||||
AREA_EFFECT_CLOUD = 3 if pv < 458 else 0
|
||||
ARMORSTAND = 78 if pv < 458 else 1
|
||||
ARROW = 60 if pv < 458 else 2
|
||||
BOAT = 1 if pv < 458 else 5
|
||||
DRAGON_FIREBALL = 93 if pv < 458 else 13
|
||||
EGG = 62 if pv < 458 else 74 # ThrownEgg
|
||||
ENDERCRYSTAL = 51 if pv < 458 else 16
|
||||
ENDERPEARL = 65 if pv < 458 else 75 # ThrownEnderpearl
|
||||
EVOCATION_FANGS = 79 if pv < 458 else 20
|
||||
EXP_BOTTLE = 75 if pv < 458 else 76 # ThrownExpBottle
|
||||
EYE_OF_ENDER = 72 if pv < 458 else 23 # EyeOfEnderSignal
|
||||
FALLING_OBJECT = 70 if pv < 458 else 24 # FallingSand
|
||||
FIREBALL = 63 if pv < 458 else 34 # Fireball (ghast)
|
||||
FIRECHARGE = 64 if pv < 458 else 65 # SmallFireball (blaze)
|
||||
FIREWORK_ROCKET = 76 if pv < 458 else 25 # FireworksRocketEntity
|
||||
FISHING_HOOK = 90 if pv < 458 else 93 # Fishing bobber
|
||||
ITEM_FRAMES = 71 if pv < 458 else 33 # ItemFrame
|
||||
ITEM_STACK = 2 if pv < 458 else 32 # Item
|
||||
LEASH_KNOT = 77 if pv < 458 else 35
|
||||
LLAMA_SPIT = 68 if pv < 458 else 37
|
||||
MINECART = 10 if pv < 458 else 39 # MinecartRideable
|
||||
POTION = 73 if pv < 458 else 77 # ThrownPotion
|
||||
SHULKER_BULLET = 67 if pv < 458 else 60
|
||||
SNOWBALL = 61 if pv < 458 else 67
|
||||
SPECTRAL_ARROW = 91 if pv < 458 else 68
|
||||
WITHER_SKULL = 66 if pv < 458 else 85
|
||||
if pv >= 393:
|
||||
TRIDENT = 94
|
||||
if pv >= 458:
|
||||
MINECART_CHEST = 40
|
||||
MINECART_COMMAND_BLOCK = 41
|
||||
MINECART_FURNACE = 42
|
||||
MINECART_HOPPER = 43
|
||||
MINECART_SPAWNER = 44
|
||||
MINECART_TNT = 45
|
||||
|
||||
setattr(cls, name, EntityType)
|
||||
return EntityType
|
||||
|
||||
def read(self, file_object):
|
||||
self.entity_id = VarInt.read(file_object)
|
||||
if self.context.protocol_version >= 49:
|
||||
self.object_uuid = UUID.read(file_object)
|
||||
self.type_id = Byte.read(file_object)
|
||||
|
||||
if self.context.protocol_version >= 458:
|
||||
self.type_id = VarInt.read(file_object)
|
||||
else:
|
||||
self.type_id = Byte.read(file_object)
|
||||
|
||||
xyz_type = Double if self.context.protocol_version >= 100 else Integer
|
||||
for attr in 'x', 'y', 'z':
|
||||
@ -64,7 +114,11 @@ class SpawnObjectPacket(Packet):
|
||||
VarInt.send(self.entity_id, packet_buffer)
|
||||
if self.context.protocol_version >= 49:
|
||||
UUID.send(self.object_uuid, packet_buffer)
|
||||
Byte.send(self.type_id, packet_buffer)
|
||||
|
||||
if self.context.protocol_version >= 458:
|
||||
VarInt.send(self.type_id, packet_buffer)
|
||||
else:
|
||||
Byte.send(self.type_id, packet_buffer)
|
||||
|
||||
xyz_type = Double if self.context.protocol_version >= 100 else Integer
|
||||
for coord in self.x, self.y, self.z:
|
||||
@ -78,9 +132,20 @@ class SpawnObjectPacket(Packet):
|
||||
Short.send(coord, packet_buffer)
|
||||
|
||||
# Access the entity type as a string, according to the EntityType enum.
|
||||
@property
|
||||
def type(self):
|
||||
if self.context is None:
|
||||
raise ValueError('This packet must have a non-None "context" '
|
||||
'in order to read the "type" property.')
|
||||
# pylint: disable=no-member
|
||||
return self.EntityType.name_from_value(self.type_id)
|
||||
|
||||
@type.setter
|
||||
def type(self, type_name):
|
||||
if self.context is None:
|
||||
raise ValueError('This packet must have a non-None "context" '
|
||||
'in order to set the "type" property.')
|
||||
self.type_id = getattr(self.EntityType, type_name)
|
||||
type = property(lambda p: p.EntityType.name_from_value(p.type_id), type)
|
||||
|
||||
# Access the fields 'x', 'y', 'z' as a Vector.
|
||||
def position(self, position):
|
||||
|
@ -61,7 +61,7 @@ class Packet(object):
|
||||
def read(self, file_object):
|
||||
for field in self.definition:
|
||||
for var_name, data_type in field.items():
|
||||
value = data_type.read(file_object)
|
||||
value = data_type.read_with_context(file_object, self.context)
|
||||
setattr(self, var_name, value)
|
||||
|
||||
# Writes a packet buffer to the socket with the appropriate headers
|
||||
@ -104,7 +104,7 @@ class Packet(object):
|
||||
for field in self.definition:
|
||||
for var_name, data_type in field.items():
|
||||
data = getattr(self, var_name)
|
||||
data_type.send(data, packet_buffer)
|
||||
data_type.send_with_context(data, packet_buffer, self.context)
|
||||
|
||||
def __repr__(self):
|
||||
str = type(self).__name__
|
||||
@ -129,7 +129,7 @@ class Packet(object):
|
||||
"""
|
||||
value = getattr(self, field, None)
|
||||
|
||||
enum_class = self.field_enum(field)
|
||||
enum_class = self.field_enum(field, self.context)
|
||||
if enum_class is not None:
|
||||
name = enum_class.name_from_value(value)
|
||||
if name is not None:
|
||||
@ -138,7 +138,7 @@ class Packet(object):
|
||||
return repr(value)
|
||||
|
||||
@classmethod
|
||||
def field_enum(cls, field):
|
||||
def field_enum(cls, field, context=None):
|
||||
""" The subclass of 'minecraft.networking.types.Enum' associated with
|
||||
this field, or None if there is no such class.
|
||||
"""
|
||||
|
@ -32,7 +32,9 @@ def get_packets(context):
|
||||
class KeepAlivePacket(AbstractKeepAlivePacket):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x0E if context.protocol_version >= 389 else \
|
||||
return 0x0F if context.protocol_version >= 471 else \
|
||||
0x10 if context.protocol_version >= 464 else \
|
||||
0x0E if context.protocol_version >= 389 else \
|
||||
0x0C if context.protocol_version >= 386 else \
|
||||
0x0B if context.protocol_version >= 345 else \
|
||||
0x0A if context.protocol_version >= 343 else \
|
||||
@ -45,7 +47,8 @@ class KeepAlivePacket(AbstractKeepAlivePacket):
|
||||
class ChatPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x02 if context.protocol_version >= 389 else \
|
||||
return 0x03 if context.protocol_version >= 464 else \
|
||||
0x02 if context.protocol_version >= 389 else \
|
||||
0x01 if context.protocol_version >= 343 else \
|
||||
0x02 if context.protocol_version >= 336 else \
|
||||
0x03 if context.protocol_version >= 318 else \
|
||||
@ -70,7 +73,9 @@ class ChatPacket(Packet):
|
||||
class PositionAndLookPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x11 if context.protocol_version >= 389 else \
|
||||
return 0x12 if context.protocol_version >= 471 else \
|
||||
0x13 if context.protocol_version >= 464 else \
|
||||
0x11 if context.protocol_version >= 389 else \
|
||||
0x0F if context.protocol_version >= 386 else \
|
||||
0x0E if context.protocol_version >= 345 else \
|
||||
0x0D if context.protocol_version >= 343 else \
|
||||
@ -101,7 +106,9 @@ class TeleportConfirmPacket(Packet):
|
||||
class AnimationPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x27 if context.protocol_version >= 389 else \
|
||||
return 0x2A if context.protocol_version >= 468 else \
|
||||
0x29 if context.protocol_version >= 464 else \
|
||||
0x27 if context.protocol_version >= 389 else \
|
||||
0x25 if context.protocol_version >= 386 else \
|
||||
0x1D if context.protocol_version >= 345 else \
|
||||
0x1C if context.protocol_version >= 343 else \
|
||||
@ -121,7 +128,8 @@ class AnimationPacket(Packet):
|
||||
class ClientStatusPacket(Packet, Enum):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x03 if context.protocol_version >= 389 else \
|
||||
return 0x04 if context.protocol_version >= 464 else \
|
||||
0x03 if context.protocol_version >= 389 else \
|
||||
0x02 if context.protocol_version >= 343 else \
|
||||
0x03 if context.protocol_version >= 336 else \
|
||||
0x04 if context.protocol_version >= 318 else \
|
||||
@ -134,7 +142,7 @@ class ClientStatusPacket(Packet, Enum):
|
||||
get_definition = staticmethod(lambda context: [
|
||||
{'action_id': VarInt}])
|
||||
field_enum = classmethod(
|
||||
lambda cls, field: cls if field == 'action_id' else None)
|
||||
lambda cls, field, context: cls if field == 'action_id' else None)
|
||||
|
||||
RESPAWN = 0
|
||||
REQUEST_STATS = 1
|
||||
@ -145,7 +153,8 @@ class ClientStatusPacket(Packet, Enum):
|
||||
class PluginMessagePacket(AbstractPluginMessagePacket):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x0A if context.protocol_version >= 389 else \
|
||||
return 0x0B if context.protocol_version >= 464 else \
|
||||
0x0A if context.protocol_version >= 389 else \
|
||||
0x09 if context.protocol_version >= 345 else \
|
||||
0x08 if context.protocol_version >= 343 else \
|
||||
0x09 if context.protocol_version >= 336 else \
|
||||
@ -170,7 +179,9 @@ class PlayerBlockPlacementPacket(Packet):
|
||||
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x29 if context.protocol_version >= 389 else \
|
||||
return 0x2C if context.protocol_version >= 468 else \
|
||||
0x2B if context.protocol_version >= 464 else \
|
||||
0x29 if context.protocol_version >= 389 else \
|
||||
0x27 if context.protocol_version >= 386 else \
|
||||
0x1F if context.protocol_version >= 345 else \
|
||||
0x1E if context.protocol_version >= 343 else \
|
||||
@ -184,12 +195,15 @@ class PlayerBlockPlacementPacket(Packet):
|
||||
@staticmethod
|
||||
def get_definition(context):
|
||||
return [
|
||||
{'hand': VarInt} if context.protocol_version >= 453 else {},
|
||||
{'location': Position},
|
||||
{'face': VarInt if context.protocol_version >= 69 else Byte},
|
||||
{'hand': VarInt},
|
||||
{'hand': VarInt} if context.protocol_version < 453 else {},
|
||||
{'x': Float if context.protocol_version >= 309 else Byte},
|
||||
{'y': Float if context.protocol_version >= 309 else Byte},
|
||||
{'z': Float if context.protocol_version >= 309 else Byte},
|
||||
({'inside_block': Boolean}
|
||||
if context.protocol_version >= 453 else {}),
|
||||
]
|
||||
|
||||
# PlayerBlockPlacementPacket.Hand is an alias for RelativeHand.
|
||||
|
@ -8,7 +8,8 @@ from minecraft.networking.types import (
|
||||
class ClientSettingsPacket(Packet):
|
||||
@staticmethod
|
||||
def get_id(context):
|
||||
return 0x04 if context.protocol_version >= 389 else \
|
||||
return 0x05 if context.protocol_version >= 464 else \
|
||||
0x04 if context.protocol_version >= 389 else \
|
||||
0x03 if context.protocol_version >= 343 else \
|
||||
0x04 if context.protocol_version >= 336 else \
|
||||
0x05 if context.protocol_version >= 318 else \
|
||||
@ -26,7 +27,7 @@ class ClientSettingsPacket(Packet):
|
||||
{'main_hand': VarInt} if context.protocol_version > 49 else {}])
|
||||
|
||||
field_enum = classmethod(
|
||||
lambda cls, field: {
|
||||
lambda cls, field, context: {
|
||||
'chat_mode': cls.ChatMode,
|
||||
'displayed_skin_parts': cls.SkinParts,
|
||||
'main_hand': AbsoluteHand,
|
||||
|
@ -20,13 +20,31 @@ __all__ = (
|
||||
class Type(object):
|
||||
__slots__ = ()
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
raise NotImplementedError("Base data type not serializable")
|
||||
@classmethod
|
||||
def read_with_context(cls, file_object, _context):
|
||||
return cls.read(file_object)
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
raise NotImplementedError("Base data type not serializable")
|
||||
@classmethod
|
||||
def send_with_context(cls, value, socket, _context):
|
||||
return cls.send(value, socket)
|
||||
|
||||
@classmethod
|
||||
def read(cls, file_object):
|
||||
if cls.read_with_context == Type.read_with_context:
|
||||
raise NotImplementedError('One of "read" or "read_with_context" '
|
||||
'must be overridden in a subclass.')
|
||||
else:
|
||||
raise TypeError('This type requires a ConnectionContext: '
|
||||
'call "read_with_context" instead of "read".')
|
||||
|
||||
@classmethod
|
||||
def send(cls, value, socket):
|
||||
if cls.send_with_context == Type.send_with_context:
|
||||
raise NotImplementedError('One of "send" or "send_with_context" '
|
||||
'must be overridden in a subclass.')
|
||||
else:
|
||||
raise TypeError('This type requires a ConnectionContext: '
|
||||
'call "send_with_context" instead of "send".')
|
||||
|
||||
|
||||
class Boolean(Type):
|
||||
@ -263,11 +281,16 @@ class Position(Type, Vector):
|
||||
__slots__ = ()
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
def read_with_context(file_object, context):
|
||||
location = UnsignedLong.read(file_object)
|
||||
x = int(location >> 38)
|
||||
y = int((location >> 26) & 0xFFF)
|
||||
z = int(location & 0x3FFFFFF)
|
||||
x = int(location >> 38) # 26 most significant bits
|
||||
|
||||
if context.protocol_version >= 443:
|
||||
z = int((location >> 12) & 0x3FFFFFF) # 26 intermediate bits
|
||||
y = int(location & 0xFFF) # 12 least signficant bits
|
||||
else:
|
||||
y = int((location >> 26) & 0xFFF) # 12 intermediate bits
|
||||
z = int(location & 0x3FFFFFF) # 26 least significant bits
|
||||
|
||||
if x >= pow(2, 25):
|
||||
x -= pow(2, 26)
|
||||
@ -281,8 +304,10 @@ class Position(Type, Vector):
|
||||
return Position(x=x, y=y, z=z)
|
||||
|
||||
@staticmethod
|
||||
def send(position, socket):
|
||||
def send_with_context(position, socket, context):
|
||||
# 'position' can be either a tuple or Position object.
|
||||
x, y, z = position
|
||||
value = ((x & 0x3FFFFFF) << 38) | ((y & 0xFFF) << 26) | (z & 0x3FFFFFF)
|
||||
value = ((x & 0x3FFFFFF) << 38 | (z & 0x3FFFFFF) << 12 | (y & 0xFFF)
|
||||
if context.protocol_version >= 443 else
|
||||
(x & 0x3FFFFFF) << 38 | (y & 0xFFF) << 26 | (z & 0x3FFFFFF))
|
||||
UnsignedLong.send(value, socket)
|
||||
|
@ -90,3 +90,50 @@ class PositionAndLook(MutableRecord):
|
||||
def look(self, look):
|
||||
self.yaw, self.pitch = look
|
||||
look = property(lambda self: (self.yaw, self.pitch), look)
|
||||
|
||||
|
||||
class descriptor(object):
|
||||
"""Behaves identically to the builtin 'property' function of Python,
|
||||
except that the getter, setter and deleter functions given by the
|
||||
user are used as the raw __get__, __set__ and __delete__ functions
|
||||
as defined in Python's descriptor protocol.
|
||||
"""
|
||||
__slots__ = '_fget', '_fset', '_fdel'
|
||||
|
||||
def __init__(self, fget=None, fset=None, fdel=None):
|
||||
self._fget = fget if fget is not None else self._default_get
|
||||
self._fset = fset if fset is not None else self._default_set
|
||||
self._fdel = fdel if fdel is not None else self._default_del
|
||||
|
||||
def getter(self, fget):
|
||||
self._fget = fget
|
||||
return self
|
||||
|
||||
def setter(self, fset):
|
||||
self._fset = fset
|
||||
return self
|
||||
|
||||
def deleter(self, fdel):
|
||||
self._fdel = fdel
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def _default_get(instance, owner):
|
||||
raise AttributeError('unreadable attribute')
|
||||
|
||||
@staticmethod
|
||||
def _default_set(instance, value):
|
||||
raise AttributeError("can't set attribute")
|
||||
|
||||
@staticmethod
|
||||
def _default_del(instance):
|
||||
raise AttributeError("can't delete attribute")
|
||||
|
||||
def __get__(self, instance, owner):
|
||||
return self._fget(self, instance, owner)
|
||||
|
||||
def __set__(self, instance, value):
|
||||
return self._fset(self, instance, value)
|
||||
|
||||
def __delete__(self, instance):
|
||||
return self._fdel(self, instance)
|
||||
|
@ -103,7 +103,7 @@ class FakeClientHandler(object):
|
||||
# Called upon entering the play state.
|
||||
self.write_packet(clientbound.play.JoinGamePacket(
|
||||
entity_id=0, game_mode=0, dimension=0, difficulty=2, max_players=1,
|
||||
level_type='default', reduced_debug_info=False))
|
||||
level_type='default', reduced_debug_info=False, render_distance=9))
|
||||
|
||||
def handle_play_packet(self, packet):
|
||||
# Called upon each packet received after handle_play_start() returns.
|
||||
|
@ -409,7 +409,7 @@ class VersionNegotiationEdgeCases(fake_server._FakeServerTest):
|
||||
status_response = '{"description": {"text": "FakeServer"}}'
|
||||
|
||||
class ClientHandler(fake_server.FakeClientHandler):
|
||||
def _run_status(self):
|
||||
def handle_status(self, request_packet):
|
||||
packet = clientbound.status.ResponsePacket()
|
||||
packet.json_response = status_response
|
||||
self.write_packet(packet)
|
||||
|
@ -187,7 +187,8 @@ class TestReadWritePackets(unittest.TestCase):
|
||||
self._test_read_write_packet(packet)
|
||||
|
||||
def test_spawn_object_packet(self):
|
||||
EntityType = clientbound.play.SpawnObjectPacket.EntityType
|
||||
EntityType = clientbound.play.SpawnObjectPacket.field_enum(
|
||||
'type_id', self.context)
|
||||
|
||||
object_uuid = 'd9568851-85bc-4a10-8d6a-261d130626fa'
|
||||
pos_look = PositionAndLook(x=68.0, y=38.0, z=76.0, yaw=16, pitch=23)
|
||||
@ -195,6 +196,7 @@ class TestReadWritePackets(unittest.TestCase):
|
||||
entity_id, type_name, type_id = 49846, 'EGG', EntityType.EGG
|
||||
|
||||
packet = clientbound.play.SpawnObjectPacket(
|
||||
context=self.context,
|
||||
x=pos_look.x, y=pos_look.y, z=pos_look.z,
|
||||
yaw=pos_look.yaw, pitch=pos_look.pitch,
|
||||
velocity_x=velocity.x, velocity_y=velocity.y,
|
||||
@ -207,9 +209,9 @@ class TestReadWritePackets(unittest.TestCase):
|
||||
self.assertEqual(packet.type, type_name)
|
||||
|
||||
packet2 = clientbound.play.SpawnObjectPacket(
|
||||
position_and_look=pos_look, velocity=velocity,
|
||||
type=type_name, object_uuid=object_uuid,
|
||||
entity_id=entity_id, data=1)
|
||||
context=self.context, position_and_look=pos_look,
|
||||
velocity=velocity, type=type_name,
|
||||
object_uuid=object_uuid, entity_id=entity_id, data=1)
|
||||
self.assertEqual(packet.__dict__, packet2.__dict__)
|
||||
|
||||
packet2.position = pos_look.position
|
||||
|
@ -51,6 +51,7 @@ class MapPacketTest(unittest.TestCase):
|
||||
packet.map_id = 1
|
||||
packet.scale = 42
|
||||
packet.is_tracking_position = True
|
||||
packet.is_locked = False
|
||||
packet.icons = []
|
||||
d_name = u'Marshmallow' if context.protocol_version >= 364 else None
|
||||
packet.icons.append(MapPacket.MapIcon(
|
||||
|
@ -8,6 +8,8 @@ from minecraft.networking.types import (
|
||||
String as StringType, Position, TrailingByteArray, UnsignedLong,
|
||||
)
|
||||
from minecraft.networking.packets import PacketBuffer
|
||||
from minecraft.networking.connection import ConnectionContext
|
||||
from minecraft import SUPPORTED_PROTOCOL_VERSIONS
|
||||
|
||||
|
||||
TEST_DATA = {
|
||||
@ -33,34 +35,50 @@ TEST_DATA = {
|
||||
|
||||
|
||||
class SerializationTest(unittest.TestCase):
|
||||
|
||||
def test_serialization(self):
|
||||
for data_type in Type.__subclasses__():
|
||||
if data_type in TEST_DATA:
|
||||
test_cases = TEST_DATA[data_type]
|
||||
for protocol_version in SUPPORTED_PROTOCOL_VERSIONS:
|
||||
context = ConnectionContext(protocol_version=protocol_version)
|
||||
|
||||
for test_data in test_cases:
|
||||
packet_buffer = PacketBuffer()
|
||||
data_type.send(test_data, packet_buffer)
|
||||
packet_buffer.reset_cursor()
|
||||
for data_type in Type.__subclasses__():
|
||||
if data_type in TEST_DATA:
|
||||
test_cases = TEST_DATA[data_type]
|
||||
|
||||
deserialized = data_type.read(packet_buffer)
|
||||
if data_type is FixedPointInteger:
|
||||
self.assertAlmostEqual(
|
||||
test_data, deserialized, delta=1.0/32.0)
|
||||
elif data_type is Float or data_type is Double:
|
||||
self.assertAlmostEquals(test_data, deserialized, 3)
|
||||
else:
|
||||
self.assertEqual(test_data, deserialized)
|
||||
for test_data in test_cases:
|
||||
packet_buffer = PacketBuffer()
|
||||
data_type.send_with_context(
|
||||
test_data, packet_buffer, context)
|
||||
packet_buffer.reset_cursor()
|
||||
|
||||
deserialized = data_type.read_with_context(
|
||||
packet_buffer, context)
|
||||
if data_type is FixedPointInteger:
|
||||
self.assertAlmostEqual(
|
||||
test_data, deserialized, delta=1.0/32.0)
|
||||
elif data_type is Float or data_type is Double:
|
||||
self.assertAlmostEquals(test_data, deserialized, 3)
|
||||
else:
|
||||
self.assertEqual(test_data, deserialized)
|
||||
|
||||
def test_exceptions(self):
|
||||
base_type = Type()
|
||||
with self.assertRaises(NotImplementedError):
|
||||
base_type.read(None)
|
||||
|
||||
with self.assertRaises(NotImplementedError):
|
||||
base_type.read_with_context(None, None)
|
||||
|
||||
with self.assertRaises(NotImplementedError):
|
||||
base_type.send(None, None)
|
||||
|
||||
with self.assertRaises(NotImplementedError):
|
||||
base_type.send_with_context(None, None, None)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
Position.read(None)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
Position.send(None, None)
|
||||
|
||||
empty_socket = PacketBuffer()
|
||||
with self.assertRaises(Exception):
|
||||
VarInt.read(empty_socket)
|
||||
|
Loading…
Reference in New Issue
Block a user