diff --git a/minecraft/__init__.py b/minecraft/__init__.py index 0be9a9e..d834d4a 100644 --- a/minecraft/__init__.py +++ b/minecraft/__init__.py @@ -3,312 +3,531 @@ A modern, Python3-compatible, well-documented library for communicating with a MineCraft server. """ +from collections import OrderedDict, namedtuple +import re + # The version number of the most recent pyCraft release. __version__ = "0.7.0" -# A dict mapping the ID string of each Minecraft version supported by pyCraft -# to the corresponding protocol version number. The ID string of a version is -# the key used to identify it in +# This bit occurs in the protocol numbers of pre-release versions after 1.16.3. +PRE = 1 << 30 + +# A record representing a Minecraft version in the following list. +Version = namedtuple('Version', ('id', 'protocol', 'supported')) + +# A list of Minecraft versions known to pyCraft, including all supported +# versions as well as some unsupported versions (used by certain forward- +# compatible code: e.g. when comparing the current protocol version with that +# of an unsupported version), in chronological order of publication. +# +# The ID string of a version is the key used to identify it in # , or the 'id' # key in "version.json" in the corresponding ".jar" file distributed by Mojang. -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, - '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, - '1.14.1 Pre-Release 1': 478, - '1.14.1 Pre-Release 2': 479, - '1.14.1': 480, - '1.14.2 Pre-Release 1': 481, - '1.14.2 Pre-Release 2': 482, - '1.14.2 Pre-Release 3': 483, - '1.14.2 Pre-Release 4': 484, - '1.14.2': 485, - '1.14.3-pre1': 486, - '1.14.3-pre2': 487, - '1.14.3-pre3': 488, - '1.14.3-pre4': 489, - '1.14.3': 490, - '1.14.4-pre1': 491, - '1.14.4-pre2': 492, - '1.14.4-pre3': 493, - '1.14.4-pre4': 494, - '1.14.4-pre5': 495, - '1.14.4-pre6': 496, - '1.14.4-pre7': 497, - '1.14.4': 498, - '19w34a': 550, - '19w35a': 551, - '19w36a': 552, - '19w37a': 553, - '19w38a': 554, - '19w38b': 555, - '19w39a': 556, - '19w40a': 557, - '19w41a': 558, - '19w42a': 559, - '19w44a': 560, - '19w45a': 561, - '19w45b': 562, - '19w46a': 563, - '19w46b': 564, - '1.15-pre1': 565, - '1.15-pre2': 566, - '1.15-pre3': 567, - '1.15-pre4': 569, - '1.15-pre5': 570, - '1.15-pre6': 571, - '1.15-pre7': 572, - '1.15': 573, - '1.15.1-pre1': 574, - '1.15.1': 575, - '1.15.2-pre1': 576, - '1.15.2-pre2': 577, - '1.15.2': 578, - '20w06a': 701, - '20w07a': 702, - '20w08a': 703, - '20w09a': 704, - '20w10a': 705, - '20w11a': 706, - '20w12a': 707, - '20w13a': 708, - '20w13b': 709, - '20w14a': 710, - '20w15a': 711, - '20w16a': 712, - '20w17a': 713, - '20w18a': 714, - '20w19a': 715, - '20w20a': 716, - '20w20b': 717, - '20w21a': 718, - '20w22a': 719, - '1.16-pre1': 721, - '1.16-pre2': 722, - '1.16-pre3': 725, - '1.16-pre4': 727, - '1.16-pre5': 729, - '1.16-pre6': 730, - '1.16-pre7': 732, - '1.16-pre8': 733, - '1.16-rc1': 734, - '1.16': 735, - '1.16.1': 736, - '20w27a': 738, - '20w28a': 740, - '20w29a': 741, - '20w30a': 743, - '1.16.2-pre1': 744, - '1.16.2-pre2': 746, - '1.16.2-pre3': 748, - '1.16.2-rc1': 749, - '1.16.2-rc2': 750, - '1.16.2': 751, - '1.16.3-rc1': 752, - '1.16.3': 753, - '1.16.4-pre1': 1073741825, - '1.16.4-pre2': 1073741826, - '1.16.4-rc1': 1073741827, - '1.16.4': 754, -} +KNOWN_MINECRAFT_VERSION_RECORDS = [ + # id protocol supported + Version('13w41a', 0, False), + Version('13w41b', 0, False), + Version('13w42a', 1, False), + Version('13w42b', 1, False), + Version('13w43a', 2, False), + Version('1.7-pre', 3, False), + Version('1.7.1-pre', 3, False), + Version('1.7.2', 4, True), + Version('13w47a', 4, False), + Version('13w47b', 4, False), + Version('13w47c', 4, False), + Version('13w47d', 4, False), + Version('13w47e', 4, False), + Version('13w48a', 4, False), + Version('13w48b', 4, False), + Version('13w49a', 4, False), + Version('1.7.3-pre', 4, False), + Version('1.7.4', 4, True), + Version('1.7.5', 4, True), + Version('1.7.6-pre1', 5, False), + Version('1.7.6-pre2', 5, False), + Version('1.7.6', 5, True), + Version('1.7.7', 5, True), + Version('1.7.8', 5, True), + Version('1.7.9', 5, True), + Version('1.7.10-pre1', 5, False), + Version('1.7.10-pre2', 5, False), + Version('1.7.10-pre3', 5, False), + Version('1.7.10-pre4', 5, False), + Version('1.7.10', 5, True), + Version('14w02a', 5, False), + Version('14w02b', 5, False), + Version('14w02c', 5, False), + Version('14w03a', 6, False), + Version('14w03b', 6, False), + Version('14w04a', 7, False), + Version('14w04b', 8, False), + Version('14w05a', 9, False), + Version('14w05b', 9, False), + Version('14w06a', 10, False), + Version('14w06b', 10, False), + Version('14w07a', 11, False), + Version('14w08a', 12, False), + Version('14w10a', 13, False), + Version('14w10b', 13, False), + Version('14w10c', 13, False), + Version('14w11a', 14, False), + Version('14w11b', 14, False), + Version('14w17a', 15, False), + Version('14w18a', 16, False), + Version('14w18b', 16, False), + Version('14w19a', 17, False), + Version('14w20a', 18, False), + Version('14w20b', 18, False), + Version('14w21a', 19, False), + Version('14w21b', 20, False), + Version('14w25a', 21, False), + Version('14w25b', 22, False), + Version('14w26a', 23, False), + Version('14w26b', 24, False), + Version('14w26c', 25, False), + Version('14w27a', 26, False), + Version('14w27b', 26, False), + Version('14w28a', 27, False), + Version('14w28b', 28, False), + Version('14w29a', 29, False), + Version('14w29a', 29, False), + Version('14w30a', 30, False), + Version('14w30b', 30, False), + Version('14w30c', 31, False), + Version('14w31a', 32, False), + Version('14w32a', 33, False), + Version('14w32b', 34, False), + Version('14w32c', 35, False), + Version('14w32d', 36, False), + Version('14w33a', 37, False), + Version('14w33b', 38, False), + Version('14w33c', 39, False), + Version('14w34a', 40, False), + Version('14w34b', 41, False), + Version('14w34c', 42, False), + Version('14w34d', 43, False), + Version('1.8-pre1', 44, False), + Version('1.8-pre2', 45, False), + Version('1.8-pre3', 46, False), + Version('1.8', 47, True), + Version('1.8.1-pre1', 47, False), + Version('1.8.1-pre2', 47, False), + Version('1.8.1-pre3', 47, False), + Version('1.8.1-pre4', 47, False), + Version('1.8.1-pre5', 47, False), + Version('1.8.1', 47, True), + Version('1.8.2-pre1', 47, False), + Version('1.8.2-pre2', 47, False), + Version('1.8.2-pre3', 47, False), + Version('1.8.2-pre4', 47, False), + Version('1.8.2-pre5', 47, False), + Version('1.8.2-pre6', 47, False), + Version('1.8.2-pre7', 47, False), + Version('1.8.2', 47, True), + Version('1.8.3', 47, True), + Version('1.8.4', 47, True), + Version('1.8.5', 47, True), + Version('1.8.6', 47, True), + Version('1.8.7', 47, True), + Version('1.8.8', 47, True), + Version('1.8.9', 47, True), + Version('15w14a', 48, False), + Version('15w31a', 49, False), + Version('15w31b', 50, False), + Version('15w31c', 51, False), + Version('15w32a', 52, False), + Version('15w32b', 53, False), + Version('15w32c', 54, False), + Version('15w33a', 55, False), + Version('15w33b', 56, False), + Version('15w33c', 57, False), + Version('15w34a', 58, False), + Version('15w34b', 59, False), + Version('15w34c', 60, False), + Version('15w34d', 61, False), + Version('15w35a', 62, False), + Version('15w35b', 63, False), + Version('15w35c', 64, False), + Version('15w35d', 65, False), + Version('15w35e', 66, False), + Version('15w36a', 67, False), + Version('15w36b', 68, False), + Version('15w36c', 69, False), + Version('15w36d', 70, False), + Version('15w37a', 71, False), + Version('15w38a', 72, False), + Version('15w38b', 73, False), + Version('15w39a', 74, False), + Version('15w39b', 74, False), + Version('15w39c', 74, False), + Version('15w40a', 75, False), + Version('15w40b', 76, False), + Version('15w41a', 77, False), + Version('15w41b', 78, False), + Version('15w42a', 79, False), + Version('15w43a', 80, False), + Version('15w43b', 81, False), + Version('15w43c', 82, False), + Version('15w44a', 83, False), + Version('15w44b', 84, False), + Version('15w45a', 85, False), + Version('15w46a', 86, False), + Version('15w47a', 87, False), + Version('15w47b', 88, False), + Version('15w47c', 89, False), + Version('15w49a', 90, False), + Version('15w49b', 91, False), + Version('15w50a', 92, False), + Version('15w51a', 93, False), + Version('15w51b', 94, False), + Version('16w02a', 95, False), + Version('16w03a', 96, False), + Version('16w04a', 97, False), + Version('16w05a', 98, False), + Version('16w05b', 99, False), + Version('16w06a', 100, False), + Version('16w07a', 101, False), + Version('16w07b', 102, False), + Version('1.9-pre1', 103, False), + Version('1.9-pre2', 104, False), + Version('1.9-pre3', 105, False), + Version('1.9-pre4', 106, False), + Version('1.9', 107, True), + Version('1.9.1-pre1', 107, False), + Version('1.9.1-pre2', 108, False), + Version('1.9.1-pre3', 108, False), + Version('1.9.1', 108, True), + Version('1.RV-Pre1', 108, False), + Version('1.9.2', 109, True), + Version('16w14a', 109, False), + Version('16w15a', 109, False), + Version('16w15b', 109, False), + Version('1.9.3-pre1', 109, False), + Version('1.9.3-pre2', 110, False), + Version('1.9.3-pre3', 110, False), + Version('1.9.3', 110, True), + Version('1.9.4', 110, True), + Version('16w20a', 201, False), + Version('16w21a', 202, False), + Version('16w21b', 203, False), + Version('1.10-pre1', 204, False), + Version('1.10-pre2', 205, False), + Version('1.10', 210, True), + Version('1.10.1', 210, True), + Version('1.10.2', 210, True), + Version('16w32a', 301, True), + Version('16w32b', 302, True), + Version('16w33a', 303, True), + Version('16w35a', 304, True), + Version('16w36a', 305, True), + Version('16w38a', 306, True), + Version('16w39a', 307, True), + Version('16w39b', 308, True), + Version('16w39c', 309, True), + Version('16w40a', 310, True), + Version('16w41a', 311, True), + Version('16w42a', 312, True), + Version('16w43a', 313, True), + Version('16w44a', 313, True), + Version('1.11-pre1', 314, True), + Version('1.11', 315, True), + Version('16w50a', 316, True), + Version('1.11.1', 316, True), + Version('1.11.2', 316, True), + Version('17w06a', 317, True), + Version('17w13a', 318, True), + Version('17w13b', 319, True), + Version('17w14a', 320, True), + Version('17w15a', 321, True), + Version('17w16a', 322, True), + Version('17w16b', 323, True), + Version('17w17a', 324, True), + Version('17w17b', 325, True), + Version('17w18a', 326, True), + Version('17w18b', 327, True), + Version('1.12-pre1', 328, True), + Version('1.12-pre2', 329, True), + Version('1.12-pre3', 330, True), + Version('1.12-pre4', 331, True), + Version('1.12-pre5', 332, True), + Version('1.12-pre6', 333, True), + Version('1.12-pre7', 334, True), + Version('1.12', 335, True), + Version('17w31a', 336, True), + Version('1.12.1-pre1', 337, True), + Version('1.12.1', 338, True), + Version('1.12.2-pre1', 339, True), + Version('1.12.2-pre2', 339, True), + Version('1.12.2', 340, True), + Version('17w43a', 341, True), + Version('17w43b', 342, True), + Version('17w45a', 343, True), + Version('17w45b', 344, True), + Version('17w46a', 345, True), + Version('17w47a', 346, True), + Version('17w47b', 347, True), + Version('17w48a', 348, True), + Version('17w49a', 349, True), + Version('17w49b', 350, True), + Version('17w50a', 351, True), + Version('18w01a', 352, True), + Version('18w02a', 353, True), + Version('18w03a', 354, True), + Version('18w03b', 355, True), + Version('18w05a', 356, True), + Version('18w06a', 357, True), + Version('18w07a', 358, True), + Version('18w07b', 359, True), + Version('18w07c', 360, True), + Version('18w08a', 361, True), + Version('18w08b', 362, True), + Version('18w09a', 363, True), + Version('18w10a', 364, True), + Version('18w10b', 365, True), + Version('18w10c', 366, True), + Version('18w10d', 367, True), + Version('18w11a', 368, True), + Version('18w14a', 369, True), + Version('18w14b', 370, True), + Version('18w15a', 371, True), + Version('18w16a', 372, True), + Version('18w19a', 373, True), + Version('18w19b', 374, True), + Version('18w20a', 375, True), + Version('18w20b', 376, True), + Version('18w20c', 377, True), + Version('18w21a', 378, True), + Version('18w21b', 379, True), + Version('18w22a', 380, True), + Version('18w22b', 381, True), + Version('18w22c', 382, True), + Version('1.13-pre1', 383, True), + Version('1.13-pre2', 384, True), + Version('1.13-pre3', 385, True), + Version('1.13-pre4', 386, True), + Version('1.13-pre5', 387, True), + Version('1.13-pre6', 388, True), + Version('1.13-pre7', 389, True), + Version('1.13-pre8', 390, True), + Version('1.13-pre9', 391, True), + Version('1.13-pre10', 392, True), + Version('1.13', 393, True), + Version('18w30a', 394, True), + Version('18w30b', 395, True), + Version('18w31a', 396, True), + Version('18w32a', 397, True), + Version('18w33a', 398, True), + Version('1.13.1-pre1', 399, True), + Version('1.13.1-pre2', 400, True), + Version('1.13.1', 401, True), + Version('1.13.2-pre1', 402, True), + Version('1.13.2-pre2', 403, True), + Version('1.13.2', 404, True), + Version('18w43a', 441, True), + Version('18w43b', 441, True), + Version('18w43c', 442, True), + Version('18w44a', 443, True), + Version('18w45a', 444, True), + Version('18w46a', 445, True), + Version('18w47a', 446, True), + Version('18w47b', 447, True), + Version('18w48a', 448, True), + Version('18w48b', 449, True), + Version('18w49a', 450, True), + Version('18w50a', 451, True), + Version('19w02a', 452, True), + Version('19w03a', 453, True), + Version('19w03b', 454, True), + Version('19w03c', 455, True), + Version('19w04a', 456, True), + Version('19w04b', 457, True), + Version('19w05a', 458, True), + Version('19w06a', 459, True), + Version('19w07a', 460, True), + Version('19w08a', 461, True), + Version('19w08b', 462, True), + Version('19w09a', 463, True), + Version('19w11a', 464, True), + Version('19w11b', 465, True), + Version('19w12a', 466, True), + Version('19w12b', 467, True), + Version('19w13a', 468, True), + Version('19w13b', 469, True), + Version('19w14a', 470, True), + Version('19w14b', 471, True), + Version('1.14 Pre-Release 1', 472, True), + Version('1.14 Pre-Release 2', 473, True), + Version('1.14 Pre-Release 3', 474, True), + Version('1.14 Pre-Release 4', 475, True), + Version('1.14 Pre-Release 5', 476, True), + Version('1.14', 477, True), + Version('1.14.1 Pre-Release 1', 478, True), + Version('1.14.1 Pre-Release 2', 479, True), + Version('1.14.1', 480, True), + Version('1.14.2 Pre-Release 1', 481, True), + Version('1.14.2 Pre-Release 2', 482, True), + Version('1.14.2 Pre-Release 3', 483, True), + Version('1.14.2 Pre-Release 4', 484, True), + Version('1.14.2', 485, True), + Version('1.14.3-pre1', 486, True), + Version('1.14.3-pre2', 487, True), + Version('1.14.3-pre3', 488, True), + Version('1.14.3-pre4', 489, True), + Version('1.14.3', 490, True), + Version('1.14.4-pre1', 491, True), + Version('1.14.4-pre2', 492, True), + Version('1.14.4-pre3', 493, True), + Version('1.14.4-pre4', 494, True), + Version('1.14.4-pre5', 495, True), + Version('1.14.4-pre6', 496, True), + Version('1.14.4-pre7', 497, True), + Version('1.14.4', 498, True), + Version('19w34a', 550, True), + Version('19w35a', 551, True), + Version('19w36a', 552, True), + Version('19w37a', 553, True), + Version('19w38a', 554, True), + Version('19w38b', 555, True), + Version('19w39a', 556, True), + Version('19w40a', 557, True), + Version('19w41a', 558, True), + Version('19w42a', 559, True), + Version('19w44a', 560, True), + Version('19w45a', 561, True), + Version('19w45b', 562, True), + Version('19w46a', 563, True), + Version('19w46b', 564, True), + Version('1.15-pre1', 565, True), + Version('1.15-pre2', 566, True), + Version('1.15-pre3', 567, True), + Version('1.15-pre4', 569, True), + Version('1.15-pre5', 570, True), + Version('1.15-pre6', 571, True), + Version('1.15-pre7', 572, True), + Version('1.15', 573, True), + Version('1.15.1-pre1', 574, True), + Version('1.15.1', 575, True), + Version('1.15.2-pre1', 576, True), + Version('1.15.2-pre2', 577, True), + Version('1.15.2', 578, True), + Version('20w06a', 701, True), + Version('20w07a', 702, True), + Version('20w08a', 703, True), + Version('20w09a', 704, True), + Version('20w10a', 705, True), + Version('20w11a', 706, True), + Version('20w12a', 707, True), + Version('20w13a', 708, True), + Version('20w13b', 709, True), + Version('20w14a', 710, True), + Version('20w15a', 711, True), + Version('20w16a', 712, True), + Version('20w17a', 713, True), + Version('20w18a', 714, True), + Version('20w19a', 715, True), + Version('20w20a', 716, True), + Version('20w20b', 717, True), + Version('20w21a', 718, True), + Version('20w22a', 719, True), + Version('1.16-pre1', 721, True), + Version('1.16-pre2', 722, True), + Version('1.16-pre3', 725, True), + Version('1.16-pre4', 727, True), + Version('1.16-pre5', 729, True), + Version('1.16-pre6', 730, True), + Version('1.16-pre7', 732, True), + Version('1.16-pre8', 733, True), + Version('1.16-rc1', 734, True), + Version('1.16', 735, True), + Version('1.16.1', 736, True), + Version('20w27a', 738, True), + Version('20w28a', 740, True), + Version('20w29a', 741, True), + Version('20w30a', 743, True), + Version('1.16.2-pre1', 744, True), + Version('1.16.2-pre2', 746, True), + Version('1.16.2-pre3', 748, True), + Version('1.16.2-rc1', 749, True), + Version('1.16.2-rc2', 750, True), + Version('1.16.2', 751, True), + Version('1.16.3-rc1', 752, True), + Version('1.16.3', 753, True), + Version('1.16.4-pre1', PRE | 1, True), + Version('1.16.4-pre2', PRE | 2, True), + Version('1.16.4-rc1', PRE | 3, True), + Version('1.16.4', 754, True), + Version('20w45a', PRE | 5, False), + Version('20w46a', PRE | 6, False), + Version('20w48a', PRE | 7, False), +] -# Those Minecraft versions supported by pyCraft which are "release" versions, -# i.e. not development snapshots or pre-release versions. -RELEASE_MINECRAFT_VERSIONS = {} +# An OrderedDict mapping the id string of each known Minecraft version to its +# protocol version number, in chronological order of release. +KNOWN_MINECRAFT_VERSIONS = OrderedDict() -# The protocol versions of SUPPORTED_MINECRAFT_VERSIONS, without duplicates, -# in ascending numerical (and hence chronological) order. +# As KNOWN_MINECRAFT_VERSIONS, but only contains versions supported by pyCraft. +SUPPORTED_MINECRAFT_VERSIONS = OrderedDict() + +# As SUPPORTED_MINECRAFT_VERSIONS, but only contains release versions. +RELEASE_MINECRAFT_VERSIONS = OrderedDict() + +# A list of the protocol version numbers in KNOWN_MINECRAFT_VERSIONS +# in the same order (chronological) but without duplicates. +KNOWN_PROTOCOL_VERSIONS = [] + +# A list of the protocol version numbers in SUPPORTED_MINECRAFT_VERSIONS +# in the same order (chronological) but without duplicates. SUPPORTED_PROTOCOL_VERSIONS = [] -# The protocol versions of RELEASE_MINECRAFT_VERSIONS, without duplicates, -# in ascending numerical (and hence chronological) order. +# A list of the protocol version numbers in RELEASE_MINECRAFT_VERSIONS +# in the same order (chronological) but without duplicates. RELEASE_PROTOCOL_VERSIONS = [] +# A dict mapping each protocol version number in KNOWN_PROTOCOL_VERSIONS to +# its index within this list (used for efficient comparison of protocol +# versions according to chronological release order). +PROTOCOL_VERSION_INDICES = {} -def initglobals(): - '''Init the globals from the SUPPORTED_MINECRAFT_VERSIONS dict - This allows the SUPPORTED_MINECRAFT_VERSIONS dict to be updated, then the - other globals can be updated as well, to allow for dynamic version support. - All updates are done by reference to allow this to work else where in the - code. +def initglobals(use_known_records=False): + '''Initialise the above global variables, using + 'SUPPORTED_MINECRAFT_VERSIONS' as the source if 'use_known_records' is + False (for backward compatibility, this is the default behaviour), or + otherwise using 'KNOWN_MINECRAFT_VERSION_RECORDS' as the source. + + This allows 'SUPPORTED_MINECRAFT_VERSIONS' or, respectively, + 'KNOWN_MINECRAFT_VERSION_RECORDS' to be updated by the library user + during runtime and then the derived data to be updated as well, to allow + for dynamic version support. All updates are done by reference to allow + this to work elsewhere in the code. ''' - global RELEASE_MINECRAFT_VERSIONS, SUPPORTED_PROTOCOL_VERSIONS - global RELEASE_PROTOCOL_VERSIONS + if use_known_records: + # Update the variables that depend on KNOWN_MINECRAFT_VERSION_RECORDS. + KNOWN_MINECRAFT_VERSIONS.clear() + KNOWN_PROTOCOL_VERSIONS.clear() + SUPPORTED_MINECRAFT_VERSIONS.clear() + PROTOCOL_VERSION_INDICES.clear() + for version in KNOWN_MINECRAFT_VERSION_RECORDS: + KNOWN_MINECRAFT_VERSIONS[version.id] = version.protocol + if version.protocol not in KNOWN_PROTOCOL_VERSIONS: + PROTOCOL_VERSION_INDICES[version.protocol] \ + = len(KNOWN_PROTOCOL_VERSIONS) + KNOWN_PROTOCOL_VERSIONS.append(version.protocol) + if version.supported: + SUPPORTED_MINECRAFT_VERSIONS[version.id] = version.protocol - import re - - for (vid, protocol) in SUPPORTED_MINECRAFT_VERSIONS.items(): - if re.match(r"\d+(\.\d+)+$", vid): - RELEASE_MINECRAFT_VERSIONS[vid] = protocol + # Update the variables that depend on SUPPORTED_MINECRAFT_VERSIONS. + SUPPORTED_PROTOCOL_VERSIONS.clear() + RELEASE_MINECRAFT_VERSIONS.clear() + RELEASE_PROTOCOL_VERSIONS.clear() + for (version_id, protocol) in SUPPORTED_MINECRAFT_VERSIONS.items(): + if re.match(r'\d+(\.\d+)+$', version_id): + RELEASE_MINECRAFT_VERSIONS[version_id] = protocol if protocol not in RELEASE_PROTOCOL_VERSIONS: RELEASE_PROTOCOL_VERSIONS.append(protocol) if protocol not in SUPPORTED_PROTOCOL_VERSIONS: SUPPORTED_PROTOCOL_VERSIONS.append(protocol) - SUPPORTED_PROTOCOL_VERSIONS.sort() - RELEASE_PROTOCOL_VERSIONS.sort() - -initglobals() +initglobals(use_known_records=True) diff --git a/minecraft/networking/connection.py b/minecraft/networking/connection.py index 5713295..c2c40ee 100644 --- a/minecraft/networking/connection.py +++ b/minecraft/networking/connection.py @@ -11,9 +11,11 @@ import re from .types import VarInt from .packets import clientbound, serverbound -from . import packets -from . import encryption -from .. import SUPPORTED_PROTOCOL_VERSIONS, SUPPORTED_MINECRAFT_VERSIONS +from . import packets, encryption +from .. import ( + utility, KNOWN_MINECRAFT_VERSIONS, SUPPORTED_MINECRAFT_VERSIONS, + SUPPORTED_PROTOCOL_VERSIONS, PROTOCOL_VERSION_INDICES +) from ..exceptions import ( VersionMismatch, LoginDisconnect, IgnorePacket, InvalidState ) @@ -31,6 +33,26 @@ class ConnectionContext(object): def __init__(self, **kwds): self.protocol_version = kwds.get('protocol_version') + def protocol_earlier(self, other_pv): + """Returns True if the protocol version of this context was published + earlier than 'other_pv', or else False.""" + return utility.protocol_earlier(self.protocol_version, other_pv) + + def protocol_earlier_eq(self, other_pv): + """Returns True if the protocol version of this context was published + earlier than, or is equal to, 'other_pv', or else False.""" + return utility.protocol_earlier_eq(self.protocol_version, other_pv) + + def protocol_later(self, other_pv): + """Returns True if the protocol version of this context was published + later than 'other_pv', or else False.""" + return utility.protocol_earlier(other_pv, self.protocol_version) + + def protocol_later_eq(self, other_pv): + """Returns True if the protocol version of this context was published + later than, or is equal to, 'other_pv', or else False.""" + return utility.protocol_earlier_eq(other_pv, self.protocol_version) + class _ConnectionOptions(object): def __init__(self, address=None, port=None, compression_threshold=-1, @@ -129,13 +151,15 @@ class Connection(object): allowed_versions = set(map(proto_version, allowed_versions)) self.allowed_proto_versions = allowed_versions + latest_allowed_proto = max(self.allowed_proto_versions, + key=PROTOCOL_VERSION_INDICES.get) + if initial_version is None: - self.default_proto_version = max(self.allowed_proto_versions) + self.default_proto_version = latest_allowed_proto else: self.default_proto_version = proto_version(initial_version) - self.context = ConnectionContext( - protocol_version=max(self.allowed_proto_versions)) + self.context = ConnectionContext(protocol_version=latest_allowed_proto) self.options = _ConnectionOptions() self.options.address = address @@ -362,7 +386,9 @@ class Connection(object): # It is important that this is set correctly even when connecting # in status mode, as some servers, e.g. SpigotMC with the # ProtocolSupport plugin, use it to determine the correct response. - self.context.protocol_version = max(self.allowed_proto_versions) + self.context.protocol_version \ + = max(self.allowed_proto_versions, + key=PROTOCOL_VERSION_INDICES.get) self.spawned = False self._connect() @@ -496,7 +522,7 @@ class Connection(object): def _version_mismatch(self, server_protocol=None, server_version=None): if server_protocol is None: - server_protocol = SUPPORTED_MINECRAFT_VERSIONS.get(server_version) + server_protocol = KNOWN_MINECRAFT_VERSIONS.get(server_version) if server_protocol is None: vs = 'version' if server_version is None else \ @@ -751,7 +777,7 @@ class PlayingReactor(PacketReactor): self.connection.write_packet(keep_alive_packet) elif packet.packet_name == "player position and look": - if self.connection.context.protocol_version >= 107: + if self.connection.context.protocol_later_eq(107): teleport_confirm = serverbound.play.TeleportConfirmPacket() teleport_confirm.teleport_id = packet.teleport_id self.connection.write_packet(teleport_confirm) diff --git a/minecraft/networking/packets/__init__.py b/minecraft/networking/packets/__init__.py index 149887c..e1028ff 100644 --- a/minecraft/networking/packets/__init__.py +++ b/minecraft/networking/packets/__init__.py @@ -1,8 +1,8 @@ ''' -NOTE: The packet classes in __all_legacy_packets__ exported by this -module are included only for backward compatibility, and should not -be used in new code, as (1) they do not include all packets present -in pyCraft, and (2) some are named oddly, for historical reasons. +NOTE: The packet classes exported by this module are included only for backward +compatibility, and should not be used in new code, as (1) they do not include +all packets present in pyCraft, and (2) some are named oddly, for historical +reasons. Use the packet classes under packets.clientbound.* and packets.serverbound.* instead. @@ -60,26 +60,3 @@ from .serverbound.play import PositionAndLookPacket from .serverbound.play import TeleportConfirmPacket from .serverbound.play import AnimationPacket as AnimationPacketServerbound from .serverbound.play import get_packets as state_playing_serverbound - -__all_legacy_packets__ = ( - state_handshake_clientbound, HandShakePacket, - state_handshake_serverbound, ResponsePacket, - PingPacketResponse, state_status_clientbound, - RequestPacket, PingPacket, state_status_serverbound, - DisconnectPacket, EncryptionRequestPacket, LoginSuccessPacket, - SetCompressionPacket, state_login_clientbound, - LoginStartPacket, EncryptionResponsePacket, - state_login_serverbound, KeepAlivePacketClientbound, - KeepAlivePacketServerbound, JoinGamePacket, ChatMessagePacket, - PlayerPositionAndLookPacket, DisconnectPacketPlayState, - SetCompressionPacketPlayState, PlayerListItemPacket, - MapPacket, state_playing_clientbound, ChatPacket, - PositionAndLookPacket, TeleportConfirmPacket, - AnimationPacketServerbound, state_playing_serverbound, - KeepAlivePacket, -) - -__all_other__ = ( - Packet, PacketBuffer, PacketListener, - AbstractKeepAlivePacket, AbstractPluginMessagePacket, -) diff --git a/minecraft/networking/packets/clientbound/login/__init__.py b/minecraft/networking/packets/clientbound/login/__init__.py index 38e0d8b..8b08dc0 100644 --- a/minecraft/networking/packets/clientbound/login/__init__.py +++ b/minecraft/networking/packets/clientbound/login/__init__.py @@ -13,7 +13,7 @@ def get_packets(context): LoginSuccessPacket, SetCompressionPacket, } - if context.protocol_version >= 385: + if context.protocol_later_eq(385): packets |= { PluginRequestPacket, } @@ -23,8 +23,8 @@ def get_packets(context): class DisconnectPacket(Packet): @staticmethod def get_id(context): - return 0x00 if context.protocol_version >= 391 else \ - 0x01 if context.protocol_version >= 385 else \ + return 0x00 if context.protocol_later_eq(391) else \ + 0x01 if context.protocol_later_eq(385) else \ 0x00 packet_name = "disconnect" @@ -35,8 +35,8 @@ class DisconnectPacket(Packet): class EncryptionRequestPacket(Packet): @staticmethod def get_id(context): - return 0x01 if context.protocol_version >= 391 else \ - 0x02 if context.protocol_version >= 385 else \ + return 0x01 if context.protocol_later_eq(391) else \ + 0x02 if context.protocol_later_eq(385) else \ 0x01 packet_name = "encryption request" @@ -49,13 +49,13 @@ class EncryptionRequestPacket(Packet): class LoginSuccessPacket(Packet): @staticmethod def get_id(context): - return 0x02 if context.protocol_version >= 391 else \ - 0x03 if context.protocol_version >= 385 else \ + return 0x02 if context.protocol_later_eq(391) else \ + 0x03 if context.protocol_later_eq(385) else \ 0x02 packet_name = "login success" get_definition = staticmethod(lambda context: [ - {'UUID': UUID if context.protocol_version >= 707 else String}, + {'UUID': UUID if context.protocol_later_eq(707) else String}, {'Username': String} ]) @@ -63,8 +63,8 @@ class LoginSuccessPacket(Packet): class SetCompressionPacket(Packet): @staticmethod def get_id(context): - return 0x03 if context.protocol_version >= 391 else \ - 0x04 if context.protocol_version >= 385 else \ + return 0x03 if context.protocol_later_eq(391) else \ + 0x04 if context.protocol_later_eq(385) else \ 0x03 packet_name = "set compression" @@ -89,7 +89,7 @@ class PluginRequestPacket(Packet): @staticmethod def get_id(context): - return 0x04 if context.protocol_version >= 391 else \ + return 0x04 if context.protocol_later_eq(391) else \ 0x00 packet_name = 'login plugin request' diff --git a/minecraft/networking/packets/clientbound/play/__init__.py b/minecraft/networking/packets/clientbound/play/__init__.py index 1afe9f6..b1c13f8 100644 --- a/minecraft/networking/packets/clientbound/play/__init__.py +++ b/minecraft/networking/packets/clientbound/play/__init__.py @@ -46,15 +46,15 @@ def get_packets(context): PlayerListHeaderAndFooterPacket, EntityLookPacket } - if context.protocol_version <= 47: + if context.protocol_earlier_eq(47): packets |= { SetCompressionPacket, } - if context.protocol_version >= 94: + if context.protocol_later_eq(94): packets |= { SoundEffectPacket, } - if context.protocol_version >= 352: + if context.protocol_later_eq(352): packets |= { FacePlayerPacket } @@ -64,32 +64,32 @@ def get_packets(context): class KeepAlivePacket(AbstractKeepAlivePacket): @staticmethod def get_id(context): - return 0x1F if context.protocol_version >= 741 else \ - 0x20 if context.protocol_version >= 721 else \ - 0x21 if context.protocol_version >= 550 else \ - 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 \ - 0x1F if context.protocol_version >= 107 else \ + return 0x1F if context.protocol_later_eq(741) else \ + 0x20 if context.protocol_later_eq(721) else \ + 0x21 if context.protocol_later_eq(550) else \ + 0x20 if context.protocol_later_eq(471) else \ + 0x21 if context.protocol_later_eq(389) else \ + 0x20 if context.protocol_later_eq(345) else \ + 0x1F if context.protocol_later_eq(332) else \ + 0x20 if context.protocol_later_eq(318) else \ + 0x1F if context.protocol_later_eq(107) else \ 0x00 class ServerDifficultyPacket(Packet): @staticmethod def get_id(context): - return 0x0D if context.protocol_version >= 721 else \ - 0x0E if context.protocol_version >= 550 else \ - 0x0D if context.protocol_version >= 332 else \ - 0x0E if context.protocol_version >= 318 else \ - 0x0D if context.protocol_version >= 70 else \ + return 0x0D if context.protocol_later_eq(721) else \ + 0x0E if context.protocol_later_eq(550) else \ + 0x0D if context.protocol_later_eq(332) else \ + 0x0E if context.protocol_later_eq(318) else \ + 0x0D if context.protocol_later_eq(70) else \ 0x41 packet_name = 'server difficulty' get_definition = staticmethod(lambda context: [ {'difficulty': UnsignedByte}, - {'is_locked': Boolean} if context.protocol_version >= 464 else {}, + {'is_locked': Boolean} if context.protocol_later_eq(464) else {}, ]) # These aliases declare the Enum type corresponding to each field: @@ -99,19 +99,19 @@ class ServerDifficultyPacket(Packet): class ChatMessagePacket(Packet): @staticmethod def get_id(context): - return 0x0E if context.protocol_version >= 721 else \ - 0x0F if context.protocol_version >= 550 else \ - 0x0E if context.protocol_version >= 343 else \ - 0x0F if context.protocol_version >= 332 else \ - 0x10 if context.protocol_version >= 317 else \ - 0x0F if context.protocol_version >= 107 else \ + return 0x0E if context.protocol_later_eq(721) else \ + 0x0F if context.protocol_later_eq(550) else \ + 0x0E if context.protocol_later_eq(343) else \ + 0x0F if context.protocol_later_eq(332) else \ + 0x10 if context.protocol_later_eq(317) else \ + 0x0F if context.protocol_later_eq(107) else \ 0x02 packet_name = "chat message" get_definition = staticmethod(lambda context: [ {'json_data': String}, {'position': Byte}, - {'sender': UUID} if context.protocol_version >= 718 else {}, + {'sender': UUID} if context.protocol_later_eq(718) else {}, ]) class Position(Enum): @@ -123,14 +123,14 @@ class ChatMessagePacket(Packet): class DisconnectPacket(Packet): @staticmethod def get_id(context): - return 0x19 if context.protocol_version >= 741 else \ - 0x1A if context.protocol_version >= 721 else \ - 0x1B if context.protocol_version >= 550 else \ - 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 \ + return 0x19 if context.protocol_later_eq(741) else \ + 0x1A if context.protocol_later_eq(721) else \ + 0x1B if context.protocol_later_eq(550) else \ + 0x1A if context.protocol_later_eq(471) else \ + 0x1B if context.protocol_later_eq(345) else \ + 0x1A if context.protocol_later_eq(332) else \ + 0x1B if context.protocol_later_eq(318) else \ + 0x1A if context.protocol_later_eq(107) else \ 0x40 packet_name = "disconnect" @@ -150,23 +150,23 @@ class SetCompressionPacket(Packet): class SpawnPlayerPacket(Packet): @staticmethod def get_id(context): - return 0x04 if context.protocol_version >= 721 else \ - 0x05 if context.protocol_version >= 67 else \ + return 0x04 if context.protocol_later_eq(721) else \ + 0x05 if context.protocol_later_eq(67) else \ 0x0C packet_name = 'spawn player' get_definition = staticmethod(lambda context: [ {'entity_id': VarInt}, {'player_UUID': UUID}, - {'x': Double} if context.protocol_version >= 100 + {'x': Double} if context.protocol_later_eq(100) else {'x': FixedPoint(Integer)}, - {'y': Double} if context.protocol_version >= 100 + {'y': Double} if context.protocol_later_eq(100) else {'y': FixedPoint(Integer)}, - {'z': Double} if context.protocol_version >= 100 + {'z': Double} if context.protocol_later_eq(100) else {'z': FixedPoint(Integer)}, {'yaw': Angle}, {'pitch': Angle}, - {'current_item': Short} if context.protocol_version <= 49 else {}, + {'current_item': Short} if context.protocol_earlier_eq(49) else {}, # TODO: read entity metadata (protocol < 550) ]) @@ -186,20 +186,20 @@ class SpawnPlayerPacket(Packet): class EntityVelocityPacket(Packet): @staticmethod def get_id(context): - return 0x46 if context.protocol_version >= 721 else \ - 0x47 if context.protocol_version >= 707 else \ - 0x46 if context.protocol_version >= 550 else \ - 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 \ - 0x3D if context.protocol_version >= 332 else \ - 0x3B if context.protocol_version >= 86 else \ - 0x3C if context.protocol_version >= 77 else \ - 0x3B if context.protocol_version >= 67 else \ + return 0x46 if context.protocol_later_eq(721) else \ + 0x47 if context.protocol_later_eq(707) else \ + 0x46 if context.protocol_later_eq(550) else \ + 0x45 if context.protocol_later_eq(471) else \ + 0x41 if context.protocol_later_eq(461) else \ + 0x42 if context.protocol_later_eq(451) else \ + 0x41 if context.protocol_later_eq(389) else \ + 0x40 if context.protocol_later_eq(352) else \ + 0x3F if context.protocol_later_eq(345) else \ + 0x3E if context.protocol_later_eq(336) else \ + 0x3D if context.protocol_later_eq(332) else \ + 0x3B if context.protocol_later_eq(86) else \ + 0x3C if context.protocol_later_eq(77) else \ + 0x3B if context.protocol_later_eq(67) else \ 0x12 packet_name = 'entity velocity' @@ -214,14 +214,14 @@ class EntityVelocityPacket(Packet): class EntityPositionDeltaPacket(Packet): @staticmethod def get_id(context): - return 0x27 if context.protocol_version >= 741 else \ - 0x28 if context.protocol_version >= 721 else \ - 0x29 if context.protocol_version >= 550 else \ - 0x28 if context.protocol_version >= 389 else \ - 0x27 if context.protocol_version >= 345 else \ - 0x26 if context.protocol_version >= 318 else \ - 0x25 if context.protocol_version >= 94 else \ - 0x26 if context.protocol_version >= 70 else \ + return 0x27 if context.protocol_later_eq(741) else \ + 0x28 if context.protocol_later_eq(721) else \ + 0x29 if context.protocol_later_eq(550) else \ + 0x28 if context.protocol_later_eq(389) else \ + 0x27 if context.protocol_later_eq(345) else \ + 0x26 if context.protocol_later_eq(318) else \ + 0x25 if context.protocol_later_eq(94) else \ + 0x26 if context.protocol_later_eq(70) else \ 0x15 packet_name = "entity position delta" @@ -229,7 +229,7 @@ class EntityPositionDeltaPacket(Packet): @staticmethod def get_definition(context): delta_type = FixedPoint(Short, 12) \ - if context.protocol_version >= 106 else \ + if context.protocol_later_eq(106) else \ FixedPoint(Byte) return [ {'entity_id': VarInt}, @@ -253,18 +253,18 @@ class EntityPositionDeltaPacket(Packet): class TimeUpdatePacket(Packet): @staticmethod def get_id(context): - return 0x4E if context.protocol_version >= 721 else \ - 0x4F if context.protocol_version >= 550 else \ - 0x4E if context.protocol_version >= 471 else \ - 0x4A if context.protocol_version >= 461 else \ - 0x4B if context.protocol_version >= 451 else \ - 0x4A if context.protocol_version >= 389 else \ - 0x49 if context.protocol_version >= 352 else \ - 0x48 if context.protocol_version >= 345 else \ - 0x47 if context.protocol_version >= 336 else \ - 0x46 if context.protocol_version >= 318 else \ - 0x44 if context.protocol_version >= 94 else \ - 0x43 if context.protocol_version >= 70 else \ + return 0x4E if context.protocol_later_eq(721) else \ + 0x4F if context.protocol_later_eq(550) else \ + 0x4E if context.protocol_later_eq(471) else \ + 0x4A if context.protocol_later_eq(461) else \ + 0x4B if context.protocol_later_eq(451) else \ + 0x4A if context.protocol_later_eq(389) else \ + 0x49 if context.protocol_later_eq(352) else \ + 0x48 if context.protocol_later_eq(345) else \ + 0x47 if context.protocol_later_eq(336) else \ + 0x46 if context.protocol_later_eq(318) else \ + 0x44 if context.protocol_later_eq(94) else \ + 0x43 if context.protocol_later_eq(70) else \ 0x03 packet_name = "time update" @@ -277,20 +277,20 @@ class TimeUpdatePacket(Packet): class UpdateHealthPacket(Packet): @staticmethod def get_id(context): - return 0x49 if context.protocol_version >= 721 else \ - 0x4A if context.protocol_version >= 707 else \ - 0x49 if context.protocol_version >= 550 else \ - 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 \ - 0x40 if context.protocol_version >= 318 else \ - 0x3E if context.protocol_version >= 86 else \ - 0x3F if context.protocol_version >= 77 else \ - 0x3E if context.protocol_version >= 67 else \ + return 0x49 if context.protocol_later_eq(721) else \ + 0x4A if context.protocol_later_eq(707) else \ + 0x49 if context.protocol_later_eq(550) else \ + 0x48 if context.protocol_later_eq(471) else \ + 0x44 if context.protocol_later_eq(461) else \ + 0x45 if context.protocol_later_eq(451) else \ + 0x44 if context.protocol_later_eq(389) else \ + 0x43 if context.protocol_later_eq(352) else \ + 0x42 if context.protocol_later_eq(345) else \ + 0x41 if context.protocol_later_eq(336) else \ + 0x40 if context.protocol_later_eq(318) else \ + 0x3E if context.protocol_later_eq(86) else \ + 0x3F if context.protocol_later_eq(77) else \ + 0x3E if context.protocol_later_eq(67) else \ 0x06 packet_name = 'update health' @@ -304,31 +304,31 @@ class UpdateHealthPacket(Packet): class PluginMessagePacket(AbstractPluginMessagePacket): @staticmethod def get_id(context): - return 0x17 if context.protocol_version >= 741 else \ - 0x18 if context.protocol_version >= 721 else \ - 0x19 if context.protocol_version >= 550 else \ - 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 \ + return 0x17 if context.protocol_later_eq(741) else \ + 0x18 if context.protocol_later_eq(721) else \ + 0x19 if context.protocol_later_eq(550) else \ + 0x18 if context.protocol_later_eq(471) else \ + 0x19 if context.protocol_later_eq(345) else \ + 0x18 if context.protocol_later_eq(332) else \ + 0x19 if context.protocol_later_eq(318) else \ + 0x18 if context.protocol_later_eq(70) else \ 0x3F class PlayerListHeaderAndFooterPacket(Packet): @staticmethod def get_id(context): - return 0x53 if context.protocol_version >= 721 else \ - 0x54 if context.protocol_version >= 550 else \ - 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 \ - 0x48 if context.protocol_version >= 107 else \ + return 0x53 if context.protocol_later_eq(721) else \ + 0x54 if context.protocol_later_eq(550) else \ + 0x53 if context.protocol_later_eq(471) else \ + 0x5F if context.protocol_later_eq(461) else \ + 0x50 if context.protocol_later_eq(451) else \ + 0x4F if context.protocol_later_eq(441) else \ + 0x4E if context.protocol_later_eq(393) else \ + 0x4A if context.protocol_later_eq(338) else \ + 0x49 if context.protocol_later_eq(335) else \ + 0x47 if context.protocol_later_eq(110) else \ + 0x48 if context.protocol_later_eq(107) else \ 0x47 packet_name = 'player list header and footer' @@ -340,14 +340,14 @@ class PlayerListHeaderAndFooterPacket(Packet): class EntityLookPacket(Packet): @staticmethod def get_id(context): - return 0x29 if context.protocol_version >= 741 else \ - 0x2A if context.protocol_version >= 721 else \ - 0x2B if context.protocol_version >= 550 else \ - 0x2A if context.protocol_version >= 389 else \ - 0x29 if context.protocol_version >= 345 else \ - 0x28 if context.protocol_version >= 318 else \ - 0x27 if context.protocol_version >= 94 else \ - 0x28 if context.protocol_version >= 70 else \ + return 0x29 if context.protocol_later_eq(741) else \ + 0x2A if context.protocol_later_eq(721) else \ + 0x2B if context.protocol_later_eq(550) else \ + 0x2A if context.protocol_later_eq(389) else \ + 0x29 if context.protocol_later_eq(345) else \ + 0x28 if context.protocol_later_eq(318) else \ + 0x27 if context.protocol_later_eq(94) else \ + 0x28 if context.protocol_later_eq(70) else \ 0x16 packet_name = 'entity look' diff --git a/minecraft/networking/packets/clientbound/play/block_change_packet.py b/minecraft/networking/packets/clientbound/play/block_change_packet.py index ca9c73f..a7c7403 100644 --- a/minecraft/networking/packets/clientbound/play/block_change_packet.py +++ b/minecraft/networking/packets/clientbound/play/block_change_packet.py @@ -9,12 +9,12 @@ from minecraft.networking.types import ( class BlockChangePacket(Packet): @staticmethod def get_id(context): - return 0x0B if context.protocol_version >= 721 else \ - 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 \ + return 0x0B if context.protocol_later_eq(721) else \ + 0x0C if context.protocol_later_eq(550) else \ + 0x0B if context.protocol_later_eq(332) else \ + 0x0C if context.protocol_later_eq(318) else \ + 0x0B if context.protocol_later_eq(67) else \ + 0x24 if context.protocol_later_eq(62) else \ 0x23 packet_name = 'block change' @@ -23,7 +23,7 @@ class BlockChangePacket(Packet): {'block_state_id': VarInt}] block_state_id = 0 - # For protocols < 347: an accessor for (block_state_id >> 4). + # For protocols before 347: an accessor for (block_state_id >> 4). @property def blockId(self): return self.block_state_id >> 4 @@ -32,7 +32,7 @@ class BlockChangePacket(Packet): 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). + # For protocols before 347: an accessor for (block_state_id & 0xF). @property def blockMeta(self): return self.block_state_id & 0xF @@ -48,13 +48,13 @@ class BlockChangePacket(Packet): class MultiBlockChangePacket(Packet): @staticmethod def get_id(context): - return 0x3B if context.protocol_version >= 741 else \ - 0x0F if context.protocol_version >= 721 else \ - 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 \ + return 0x3B if context.protocol_later_eq(741) else \ + 0x0F if context.protocol_later_eq(721) else \ + 0x10 if context.protocol_later_eq(550) else \ + 0x0F if context.protocol_later_eq(343) else \ + 0x10 if context.protocol_later_eq(332) else \ + 0x11 if context.protocol_later_eq(318) else \ + 0x10 if context.protocol_later_eq(67) else \ 0x22 packet_name = 'multi block change' @@ -87,7 +87,7 @@ class MultiBlockChangePacket(Packet): # 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). + # For protocols before 347: an accessor for (block_state_id >> 4). @property def blockId(self): return self.block_state_id >> 4 @@ -96,7 +96,7 @@ class MultiBlockChangePacket(Packet): 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). + # For protocols before 347: an accessor for (block_state_id & 0xF). @property def blockMeta(self): return self.block_state_id & 0xF @@ -111,7 +111,7 @@ class MultiBlockChangePacket(Packet): @classmethod def read_with_context(cls, file_object, context): record = cls() - if context.protocol_version >= 741: + if context.protocol_later_eq(741): value = VarLong.read(file_object) record.block_state_id = value >> 12 record.x = (value >> 8) & 0xF @@ -127,7 +127,7 @@ class MultiBlockChangePacket(Packet): @classmethod def send_with_context(self, record, socket, context): - if context.protocol_version >= 741: + if context.protocol_later_eq(741): value = record.block_state_id << 12 | \ (record.x & 0xF) << 8 | \ (record.z & 0xF) << 4 | \ @@ -141,9 +141,9 @@ class MultiBlockChangePacket(Packet): get_definition = staticmethod(lambda context: [ {'chunk_section_pos': MultiBlockChangePacket.ChunkSectionPos}, {'invert_trust_edges': Boolean} - if context.protocol_version >= 748 else {}, # Provisional field name. + if context.protocol_later_eq(748) else {}, # Provisional field name. {'records': PrefixedArray(VarInt, MultiBlockChangePacket.Record)}, - ] if context.protocol_version >= 741 else [ + ] if context.protocol_later_eq(741) else [ {'chunk_x': Integer}, {'chunk_z': Integer}, {'records': PrefixedArray(VarInt, MultiBlockChangePacket.Record)}, diff --git a/minecraft/networking/packets/clientbound/play/combat_event_packet.py b/minecraft/networking/packets/clientbound/play/combat_event_packet.py index db53734..b06fc0c 100644 --- a/minecraft/networking/packets/clientbound/play/combat_event_packet.py +++ b/minecraft/networking/packets/clientbound/play/combat_event_packet.py @@ -8,19 +8,19 @@ from minecraft.networking.types import ( class CombatEventPacket(Packet): @staticmethod def get_id(context): - return 0x31 if context.protocol_version >= 741 else \ - 0x32 if context.protocol_version >= 721 else \ - 0x33 if context.protocol_version >= 550 else \ - 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 \ - 0x2D if context.protocol_version >= 318 else \ - 0x2C if context.protocol_version >= 86 else \ - 0x2D if context.protocol_version >= 80 else \ - 0x2C if context.protocol_version >= 67 else \ + return 0x31 if context.protocol_later_eq(741) else \ + 0x32 if context.protocol_later_eq(721) else \ + 0x33 if context.protocol_later_eq(550) else \ + 0x32 if context.protocol_later_eq(471) else \ + 0x30 if context.protocol_later_eq(451) else \ + 0x2F if context.protocol_later_eq(389) else \ + 0x2E if context.protocol_later_eq(345) else \ + 0x2D if context.protocol_later_eq(336) else \ + 0x2C if context.protocol_later_eq(332) else \ + 0x2D if context.protocol_later_eq(318) else \ + 0x2C if context.protocol_later_eq(86) else \ + 0x2D if context.protocol_later_eq(80) else \ + 0x2C if context.protocol_later_eq(67) else \ 0x42 packet_name = 'combat event' diff --git a/minecraft/networking/packets/clientbound/play/explosion_packet.py b/minecraft/networking/packets/clientbound/play/explosion_packet.py index 71a4af2..fe2745e 100644 --- a/minecraft/networking/packets/clientbound/play/explosion_packet.py +++ b/minecraft/networking/packets/clientbound/play/explosion_packet.py @@ -7,16 +7,16 @@ from minecraft.networking.packets import Packet class ExplosionPacket(Packet): @staticmethod def get_id(context): - return 0x1B if context.protocol_version >= 741 else \ - 0x1C if context.protocol_version >= 721 else \ - 0x1D if context.protocol_version >= 550 else \ - 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 \ - 0x1C if context.protocol_version >= 80 else \ - 0x1B if context.protocol_version >= 67 else \ + return 0x1B if context.protocol_later_eq(741) else \ + 0x1C if context.protocol_later_eq(721) else \ + 0x1D if context.protocol_later_eq(550) else \ + 0x1C if context.protocol_later_eq(471) else \ + 0x1E if context.protocol_later_eq(389) else \ + 0x1D if context.protocol_later_eq(345) else \ + 0x1C if context.protocol_later_eq(332) else \ + 0x1D if context.protocol_later_eq(318) else \ + 0x1C if context.protocol_later_eq(80) else \ + 0x1B if context.protocol_later_eq(67) else \ 0x27 packet_name = 'explosion' diff --git a/minecraft/networking/packets/clientbound/play/face_player_packet.py b/minecraft/networking/packets/clientbound/play/face_player_packet.py index 4aca89d..4af3b76 100644 --- a/minecraft/networking/packets/clientbound/play/face_player_packet.py +++ b/minecraft/networking/packets/clientbound/play/face_player_packet.py @@ -8,12 +8,12 @@ from minecraft.networking.packets import Packet class FacePlayerPacket(Packet): @staticmethod def get_id(context): - return 0x33 if context.protocol_version >= 741 else \ - 0x34 if context.protocol_version >= 721 else \ - 0x35 if context.protocol_version >= 550 else \ - 0x34 if context.protocol_version >= 471 else \ - 0x32 if context.protocol_version >= 451 else \ - 0x31 if context.protocol_version >= 389 else \ + return 0x33 if context.protocol_later_eq(741) else \ + 0x34 if context.protocol_later_eq(721) else \ + 0x35 if context.protocol_later_eq(550) else \ + 0x34 if context.protocol_later_eq(471) else \ + 0x32 if context.protocol_later_eq(451) else \ + 0x31 if context.protocol_later_eq(389) else \ 0x30 packet_name = 'face player' @@ -21,14 +21,14 @@ class FacePlayerPacket(Packet): @property def fields(self): return ('origin', 'x', 'y', 'z', 'entity_id', 'entity_origin') \ - if self.context.protocol_version >= 353 else \ + if self.context.protocol_later_eq(353) else \ ('entity_id', 'x', 'y', 'z') # Access the 'x', 'y', 'z' fields as a Vector tuple. target = multi_attribute_alias(Vector, 'x', 'y', 'z') def read(self, file_object): - if self.context.protocol_version >= 353: + if self.context.protocol_later_eq(353): self.origin = VarInt.read(file_object) self.x = Double.read(file_object) self.y = Double.read(file_object) @@ -51,7 +51,7 @@ class FacePlayerPacket(Packet): self.z = Double.read(file_object) def write_fields(self, packet_buffer): - if self.context.protocol_version >= 353: + if self.context.protocol_later_eq(353): VarInt.send(self.origin, packet_buffer) Double.send(self.x, packet_buffer) Double.send(self.y, packet_buffer) diff --git a/minecraft/networking/packets/clientbound/play/join_game_and_respawn_packets.py b/minecraft/networking/packets/clientbound/play/join_game_and_respawn_packets.py index f94a07b..109d27d 100644 --- a/minecraft/networking/packets/clientbound/play/join_game_and_respawn_packets.py +++ b/minecraft/networking/packets/clientbound/play/join_game_and_respawn_packets.py @@ -48,9 +48,9 @@ class AbstractDimensionPacket(Packet): ''' def field_string(self, field): # pylint: disable=no-member - if self.context.protocol_version >= 748 and field == 'dimension': + if self.context.protocol_later_eq(748) and field == 'dimension': return nbt_to_snbt(self.dimension) - elif self.context.protocol_version < 718 and field == 'dimension': + elif self.context.protocol_earlier(718) and field == 'dimension': return Dimension.name_from_value(self.dimension) return super(AbstractDimensionPacket, self).field_string(field) @@ -58,43 +58,43 @@ class AbstractDimensionPacket(Packet): class JoinGamePacket(AbstractDimensionPacket): @staticmethod def get_id(context): - return 0x24 if context.protocol_version >= 741 else \ - 0x25 if context.protocol_version >= 721 else \ - 0x26 if context.protocol_version >= 550 else \ - 0x25 if context.protocol_version >= 389 else \ - 0x24 if context.protocol_version >= 345 else \ - 0x23 if context.protocol_version >= 332 else \ - 0x24 if context.protocol_version >= 318 else \ - 0x23 if context.protocol_version >= 107 else \ + return 0x24 if context.protocol_later_eq(741) else \ + 0x25 if context.protocol_later_eq(721) else \ + 0x26 if context.protocol_later_eq(550) else \ + 0x25 if context.protocol_later_eq(389) else \ + 0x24 if context.protocol_later_eq(345) else \ + 0x23 if context.protocol_later_eq(332) else \ + 0x24 if context.protocol_later_eq(318) else \ + 0x23 if context.protocol_later_eq(107) else \ 0x01 packet_name = "join game" get_definition = staticmethod(lambda context: [ {'entity_id': Integer}, - {'is_hardcore': Boolean} if context.protocol_version >= 738 else {}, + {'is_hardcore': Boolean} if context.protocol_later_eq(738) else {}, {'game_mode': UnsignedByte}, {'previous_game_mode': UnsignedByte} - if context.protocol_version >= 730 else {}, + if context.protocol_later_eq(730) else {}, {'world_names': PrefixedArray(VarInt, String)} - if context.protocol_version >= 722 else {}, + if context.protocol_later_eq(722) else {}, {'dimension_codec': NBT} - if context.protocol_version >= 718 else {}, + if context.protocol_later_eq(718) else {}, {'dimension': - NBT if context.protocol_version >= 748 else - String if context.protocol_version >= 718 else - Integer if context.protocol_version >= 108 else + NBT if context.protocol_later_eq(748) else + String if context.protocol_later_eq(718) else + Integer if context.protocol_later_eq(108) else Byte}, - {'world_name': String} if context.protocol_version >= 722 else {}, - {'hashed_seed': Long} if context.protocol_version >= 552 else {}, - {'difficulty': UnsignedByte} if context.protocol_version < 464 else {}, + {'world_name': String} if context.protocol_later_eq(722) else {}, + {'hashed_seed': Long} if context.protocol_later_eq(552) else {}, + {'difficulty': UnsignedByte} if context.protocol_earlier(464) else {}, {'max_players': - VarInt if context.protocol_version >= 749 else UnsignedByte}, - {'level_type': String} if context.protocol_version < 716 else {}, - {'render_distance': VarInt} if context.protocol_version >= 468 else {}, + VarInt if context.protocol_later_eq(749) else UnsignedByte}, + {'level_type': String} if context.protocol_earlier(716) else {}, + {'render_distance': VarInt} if context.protocol_later_eq(468) else {}, {'reduced_debug_info': Boolean}, - {'respawn_screen': Boolean} if context.protocol_version >= 571 else {}, - {'is_debug': Boolean} if context.protocol_version >= 716 else {}, - {'is_flat': Boolean} if context.protocol_version >= 716 else {}, + {'respawn_screen': Boolean} if context.protocol_later_eq(571) else {}, + {'is_debug': Boolean} if context.protocol_later_eq(716) else {}, + {'is_flat': Boolean} if context.protocol_later_eq(716) else {}, ]) # These aliases declare the Enum type corresponding to each field: @@ -105,7 +105,7 @@ class JoinGamePacket(AbstractDimensionPacket): # Can be set or deleted when 'context' is undefined. @property def game_mode(self): - if self.context.protocol_version >= 738: + if self.context.protocol_later_eq(738): return self._game_mode_738 else: return self._game_mode_0 @@ -124,7 +124,7 @@ class JoinGamePacket(AbstractDimensionPacket): # Can be set or deleted when 'context' is undefined. @property def is_hardcore(self): - if self.context.protocol_version >= 738: + if self.context.protocol_later_eq(738): return self._is_hardcore else: return bool(self._game_mode_0 & GameMode.HARDCORE) @@ -148,7 +148,7 @@ class JoinGamePacket(AbstractDimensionPacket): # version-independently. Can be set or deleted when 'context' is undefined. @property def pure_game_mode(self): - if self.context.protocol_version >= 738: + if self.context.protocol_later_eq(738): return self._game_mode_738 else: return self._game_mode_0 & ~GameMode.HARDCORE @@ -170,37 +170,37 @@ class JoinGamePacket(AbstractDimensionPacket): class RespawnPacket(AbstractDimensionPacket): @staticmethod def get_id(context): - return 0x39 if context.protocol_version >= 741 else \ - 0x3A if context.protocol_version >= 721 else \ - 0x3B if context.protocol_version >= 550 else \ - 0x3A if context.protocol_version >= 471 else \ - 0x38 if context.protocol_version >= 461 else \ - 0x39 if context.protocol_version >= 451 else \ - 0x38 if context.protocol_version >= 389 else \ - 0x37 if context.protocol_version >= 352 else \ - 0x36 if context.protocol_version >= 345 else \ - 0x35 if context.protocol_version >= 336 else \ - 0x34 if context.protocol_version >= 332 else \ - 0x35 if context.protocol_version >= 318 else \ - 0x33 if context.protocol_version >= 70 else \ + return 0x39 if context.protocol_later_eq(741) else \ + 0x3A if context.protocol_later_eq(721) else \ + 0x3B if context.protocol_later_eq(550) else \ + 0x3A if context.protocol_later_eq(471) else \ + 0x38 if context.protocol_later_eq(461) else \ + 0x39 if context.protocol_later_eq(451) else \ + 0x38 if context.protocol_later_eq(389) else \ + 0x37 if context.protocol_later_eq(352) else \ + 0x36 if context.protocol_later_eq(345) else \ + 0x35 if context.protocol_later_eq(336) else \ + 0x34 if context.protocol_later_eq(332) else \ + 0x35 if context.protocol_later_eq(318) else \ + 0x33 if context.protocol_later_eq(70) else \ 0x07 packet_name = 'respawn' get_definition = staticmethod(lambda context: [ {'dimension': - NBT if context.protocol_version >= 748 else - String if context.protocol_version >= 718 else + NBT if context.protocol_later_eq(748) else + String if context.protocol_later_eq(718) else Integer}, - {'world_name': String} if context.protocol_version >= 719 else {}, - {'difficulty': UnsignedByte} if context.protocol_version < 464 else {}, - {'hashed_seed': Long} if context.protocol_version >= 552 else {}, + {'world_name': String} if context.protocol_later_eq(719) else {}, + {'difficulty': UnsignedByte} if context.protocol_earlier(464) else {}, + {'hashed_seed': Long} if context.protocol_later_eq(552) else {}, {'game_mode': UnsignedByte}, {'previous_game_mode': UnsignedByte} - if context.protocol_version >= 730 else {}, - {'level_type': String} if context.protocol_version < 716 else {}, - {'is_debug': Boolean} if context.protocol_version >= 716 else {}, - {'is_flat': Boolean} if context.protocol_version >= 716 else {}, - {'copy_metadata': Boolean} if context.protocol_version >= 714 else {}, + if context.protocol_later_eq(730) else {}, + {'level_type': String} if context.protocol_earlier(716) else {}, + {'is_debug': Boolean} if context.protocol_later_eq(716) else {}, + {'is_flat': Boolean} if context.protocol_later_eq(716) else {}, + {'copy_metadata': Boolean} if context.protocol_later_eq(714) else {}, ]) # These aliases declare the Enum type corresponding to each field: diff --git a/minecraft/networking/packets/clientbound/play/map_packet.py b/minecraft/networking/packets/clientbound/play/map_packet.py index 3de187b..490cf87 100644 --- a/minecraft/networking/packets/clientbound/play/map_packet.py +++ b/minecraft/networking/packets/clientbound/play/map_packet.py @@ -8,14 +8,14 @@ from minecraft.networking.types import ( class MapPacket(Packet): @staticmethod def get_id(context): - return 0x25 if context.protocol_version >= 741 else \ - 0x26 if context.protocol_version >= 721 else \ - 0x27 if context.protocol_version >= 550 else \ - 0x26 if context.protocol_version >= 389 else \ - 0x25 if context.protocol_version >= 345 else \ - 0x24 if context.protocol_version >= 334 else \ - 0x25 if context.protocol_version >= 318 else \ - 0x24 if context.protocol_version >= 107 else \ + return 0x25 if context.protocol_later_eq(741) else \ + 0x26 if context.protocol_later_eq(721) else \ + 0x27 if context.protocol_later_eq(550) else \ + 0x26 if context.protocol_later_eq(389) else \ + 0x25 if context.protocol_later_eq(345) else \ + 0x24 if context.protocol_later_eq(334) else \ + 0x25 if context.protocol_later_eq(318) else \ + 0x24 if context.protocol_later_eq(107) else \ 0x34 packet_name = 'map' @@ -23,9 +23,9 @@ class MapPacket(Packet): @property def fields(self): fields = 'id', 'scale', 'icons', 'width', 'height', 'pixels' - if self.context.protocol_version >= 107: + if self.context.protocol_later_eq(107): fields += 'is_tracking_position', - if self.context.protocol_version >= 452: + if self.context.protocol_later_eq(452): fields += 'is_locked', return fields @@ -71,12 +71,12 @@ class MapPacket(Packet): self.map_id = VarInt.read(file_object) self.scale = Byte.read(file_object) - if self.context.protocol_version >= 107: + if self.context.protocol_later_eq(107): self.is_tracking_position = Boolean.read(file_object) else: self.is_tracking_position = True - if self.context.protocol_version >= 452: + if self.context.protocol_later_eq(452): self.is_locked = Boolean.read(file_object) else: self.is_locked = False @@ -84,15 +84,15 @@ class MapPacket(Packet): icon_count = VarInt.read(file_object) self.icons = [] for i in range(icon_count): - if self.context.protocol_version >= 373: + if self.context.protocol_later_eq(373): type = VarInt.read(file_object) else: type, direction = divmod(UnsignedByte.read(file_object), 16) x = Byte.read(file_object) z = Byte.read(file_object) - if self.context.protocol_version >= 373: + if self.context.protocol_later_eq(373): direction = UnsignedByte.read(file_object) - if self.context.protocol_version >= 364: + if self.context.protocol_later_eq(364): has_name = Boolean.read(file_object) display_name = String.read(file_object) if has_name else None else: @@ -134,12 +134,12 @@ class MapPacket(Packet): def write_fields(self, packet_buffer): VarInt.send(self.map_id, packet_buffer) Byte.send(self.scale, packet_buffer) - if self.context.protocol_version >= 107: + if self.context.protocol_later_eq(107): Boolean.send(self.is_tracking_position, packet_buffer) VarInt.send(len(self.icons), packet_buffer) for icon in self.icons: - if self.context.protocol_version >= 373: + if self.context.protocol_later_eq(373): VarInt.send(icon.type, packet_buffer) else: type_and_direction = (icon.type << 4) & 0xF0 @@ -147,9 +147,9 @@ class MapPacket(Packet): UnsignedByte.send(type_and_direction, packet_buffer) Byte.send(icon.location[0], packet_buffer) Byte.send(icon.location[1], packet_buffer) - if self.context.protocol_version >= 373: + if self.context.protocol_later_eq(373): UnsignedByte.send(icon.direction, packet_buffer) - if self.context.protocol_version >= 364: + if self.context.protocol_later_eq(364): Boolean.send(icon.display_name is not None, packet_buffer) if icon.display_name is not None: String.send(icon.display_name, packet_buffer) diff --git a/minecraft/networking/packets/clientbound/play/player_list_item_packet.py b/minecraft/networking/packets/clientbound/play/player_list_item_packet.py index 6f85fd0..74880e7 100644 --- a/minecraft/networking/packets/clientbound/play/player_list_item_packet.py +++ b/minecraft/networking/packets/clientbound/play/player_list_item_packet.py @@ -9,17 +9,17 @@ from minecraft.networking.types import ( class PlayerListItemPacket(Packet): @staticmethod def get_id(context): - return 0x32 if context.protocol_version >= 741 else \ - 0x33 if context.protocol_version >= 721 else \ - 0x34 if context.protocol_version >= 550 else \ - 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 \ - 0x2E if context.protocol_version >= 318 else \ - 0x2D if context.protocol_version >= 107 else \ + return 0x32 if context.protocol_later_eq(741) else \ + 0x33 if context.protocol_later_eq(721) else \ + 0x34 if context.protocol_later_eq(550) else \ + 0x33 if context.protocol_later_eq(471) else \ + 0x31 if context.protocol_later_eq(451) else \ + 0x30 if context.protocol_later_eq(389) else \ + 0x2F if context.protocol_later_eq(345) else \ + 0x2E if context.protocol_later_eq(336) else \ + 0x2D if context.protocol_later_eq(332) else \ + 0x2E if context.protocol_later_eq(318) else \ + 0x2D if context.protocol_later_eq(107) else \ 0x38 packet_name = "player list item" diff --git a/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py b/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py index 5169366..59574e5 100644 --- a/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py +++ b/minecraft/networking/packets/clientbound/play/player_position_and_look_packet.py @@ -9,18 +9,18 @@ from minecraft.networking.types import ( class PlayerPositionAndLookPacket(Packet, BitFieldEnum): @staticmethod def get_id(context): - return 0x34 if context.protocol_version >= 741 else \ - 0x35 if context.protocol_version >= 721 else \ - 0x36 if context.protocol_version >= 550 else \ - 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 \ - 0x2E if context.protocol_version >= 332 else \ - 0x2F if context.protocol_version >= 318 else \ - 0x2E if context.protocol_version >= 70 else \ + return 0x34 if context.protocol_later_eq(741) else \ + 0x35 if context.protocol_later_eq(721) else \ + 0x36 if context.protocol_later_eq(550) else \ + 0x35 if context.protocol_later_eq(471) else \ + 0x33 if context.protocol_later_eq(451) else \ + 0x32 if context.protocol_later_eq(389) else \ + 0x31 if context.protocol_later_eq(352) else \ + 0x30 if context.protocol_later_eq(345) else \ + 0x2F if context.protocol_later_eq(336) else \ + 0x2E if context.protocol_later_eq(332) else \ + 0x2F if context.protocol_later_eq(318) else \ + 0x2E if context.protocol_later_eq(70) else \ 0x08 packet_name = "player position and look" @@ -31,7 +31,7 @@ class PlayerPositionAndLookPacket(Packet, BitFieldEnum): {'yaw': Float}, {'pitch': Float}, {'flags': Byte}, - {'teleport_id': VarInt} if context.protocol_version >= 107 else {}, + {'teleport_id': VarInt} if context.protocol_later_eq(107) else {}, ]) # Access the 'x', 'y', 'z' fields as a Vector tuple. diff --git a/minecraft/networking/packets/clientbound/play/sound_effect_packet.py b/minecraft/networking/packets/clientbound/play/sound_effect_packet.py index da56748..697e2d1 100644 --- a/minecraft/networking/packets/clientbound/play/sound_effect_packet.py +++ b/minecraft/networking/packets/clientbound/play/sound_effect_packet.py @@ -9,18 +9,18 @@ __all__ = 'SoundEffectPacket', class SoundEffectPacket(Packet): @staticmethod def get_id(context): - return 0x51 if context.protocol_version >= 721 else \ - 0x52 if context.protocol_version >= 550 else \ - 0x51 if context.protocol_version >= 471 else \ - 0x4D if context.protocol_version >= 461 else \ - 0x4E if context.protocol_version >= 451 else \ - 0x4D if context.protocol_version >= 389 else \ - 0x4C if context.protocol_version >= 352 else \ - 0x4B if context.protocol_version >= 345 else \ - 0x4A if context.protocol_version >= 343 else \ - 0x49 if context.protocol_version >= 336 else \ - 0x48 if context.protocol_version >= 318 else \ - 0x46 if context.protocol_version >= 110 else \ + return 0x51 if context.protocol_later_eq(721) else \ + 0x52 if context.protocol_later_eq(550) else \ + 0x51 if context.protocol_later_eq(471) else \ + 0x4D if context.protocol_later_eq(461) else \ + 0x4E if context.protocol_later_eq(451) else \ + 0x4D if context.protocol_later_eq(389) else \ + 0x4C if context.protocol_later_eq(352) else \ + 0x4B if context.protocol_later_eq(345) else \ + 0x4A if context.protocol_later_eq(343) else \ + 0x49 if context.protocol_later_eq(336) else \ + 0x48 if context.protocol_later_eq(318) else \ + 0x46 if context.protocol_later_eq(110) else \ 0x47 packet_name = 'sound effect' @@ -29,13 +29,16 @@ class SoundEffectPacket(Packet): def get_definition(context): return [ ({'sound_category': VarInt} - if 326 > context.protocol_version >= 321 else {}), + if context.protocol_later_eq(321) + and context.protocol_earlier(326) else {}), {'sound_id': VarInt}, ({'sound_category': VarInt} - if 95 <= context.protocol_version < 321 - or context.protocol_version >= 326 else {}), + if context.protocol_later_eq(95) + and context.protocol_earlier(321) + or context.protocol_later_eq(326) else {}), ({'parroted_entity_type': String} - if 326 > context.protocol_version >= 321 else {}), + if context.protocol_later_eq(321) + and context.protocol_earlier(326) else {}), {'effect_position': SoundEffectPacket.EffectPosition}, {'volume': Float}, {'pitch': SoundEffectPacket.Pitch}, @@ -66,19 +69,19 @@ class SoundEffectPacket(Packet): class Pitch(Type): @staticmethod def read_with_context(file_object, context): - if context.protocol_version >= 201: + if context.protocol_later_eq(201): value = Float.read(file_object) else: value = Byte.read(file_object) - if context.protocol_version < 204: + if context.protocol_earlier(204): value /= 63.5 return value @staticmethod def send_with_context(value, socket, context): - if context.protocol_version < 204: + if context.protocol_earlier(204): value *= 63.5 - if context.protocol_version >= 201: + if context.protocol_later_eq(201): Float.send(value, socket) else: Byte.send(int(value), socket) diff --git a/minecraft/networking/packets/clientbound/play/spawn_object_packet.py b/minecraft/networking/packets/clientbound/play/spawn_object_packet.py index c129b72..9756e4f 100644 --- a/minecraft/networking/packets/clientbound/play/spawn_object_packet.py +++ b/minecraft/networking/packets/clientbound/play/spawn_object_packet.py @@ -10,7 +10,7 @@ from minecraft.networking.types import ( class SpawnObjectPacket(Packet): @staticmethod def get_id(context): - return 0x00 if context.protocol_version >= 67 else \ + return 0x00 if context.protocol_later_eq(67) else \ 0x0E packet_name = 'spawn object' @@ -43,43 +43,44 @@ class SpawnObjectPacket(Packet): if field != 'type_id' or context is None: return - pv = context.protocol_version - name = 'EntityType_%d' % pv + name = 'EntityType_%d' % context.protocol_version if hasattr(cls, name): return getattr(cls, name) + era = 0 if context.protocol_earlier(458) else 1 + class EntityType(Enum): # XXX This has not been updated for >= v1.15 - 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: + ACTIVATED_TNT = (50, 55)[era] # PrimedTnt + AREA_EFFECT_CLOUD = ( 3, 0)[era] + ARMORSTAND = (78, 1)[era] + ARROW = (60, 2)[era] + BOAT = ( 1, 5)[era] + DRAGON_FIREBALL = (93, 13)[era] + EGG = (62, 74)[era] # ThrownEgg + ENDERCRYSTAL = (51, 16)[era] + ENDERPEARL = (65, 75)[era] # ThrownEnderpearl + EVOCATION_FANGS = (79, 20)[era] + EXP_BOTTLE = (75, 76)[era] # ThrownExpBottle + EYE_OF_ENDER = (72, 23)[era] # EyeOfEnderSignal + FALLING_OBJECT = (70, 24)[era] # FallingSand + FIREBALL = (63, 34)[era] # Fireball (ghast) + FIRECHARGE = (64, 65)[era] # SmallFireball (blaze) + FIREWORK_ROCKET = (76, 25)[era] # FireworksRocketEntity + FISHING_HOOK = (90, 93)[era] # Fishing bobber + ITEM_FRAMES = (71, 33)[era] # ItemFrame + ITEM_STACK = ( 2, 32)[era] # Item + LEASH_KNOT = (77, 35)[era] + LLAMA_SPIT = (68, 37)[era] + MINECART = (10, 39)[era] # MinecartRideable + POTION = (73, 77)[era] # ThrownPotion + SHULKER_BULLET = (67, 60)[era] + SNOWBALL = (61, 67)[era] + SPECTRAL_ARROW = (91, 68)[era] + WITHER_SKULL = (66, 85)[era] + if context.protocol_later_eq(393): TRIDENT = 94 - if pv >= 458: + if context.protocol_later_eq(458): MINECART_CHEST = 40 MINECART_COMMAND_BLOCK = 41 MINECART_FURNACE = 42 @@ -92,44 +93,44 @@ class SpawnObjectPacket(Packet): def read(self, file_object): self.entity_id = VarInt.read(file_object) - if self.context.protocol_version >= 49: + if self.context.protocol_later_eq(49): self.object_uuid = UUID.read(file_object) - if self.context.protocol_version >= 458: + if self.context.protocol_later_eq(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 + xyz_type = Double if self.context.protocol_later_eq(100) else Integer for attr in 'x', 'y', 'z': setattr(self, attr, xyz_type.read(file_object)) for attr in 'pitch', 'yaw': setattr(self, attr, Angle.read(file_object)) self.data = Integer.read(file_object) - if self.context.protocol_version >= 49 or self.data > 0: + if self.context.protocol_later_eq(49) or self.data > 0: for attr in 'velocity_x', 'velocity_y', 'velocity_z': setattr(self, attr, Short.read(file_object)) def write_fields(self, packet_buffer): VarInt.send(self.entity_id, packet_buffer) - if self.context.protocol_version >= 49: + if self.context.protocol_later_eq(49): UUID.send(self.object_uuid, packet_buffer) - if self.context.protocol_version >= 458: + if self.context.protocol_later_eq(458): VarInt.send(self.type_id, packet_buffer) else: Byte.send(self.type_id, packet_buffer) # pylint: disable=no-member - xyz_type = Double if self.context.protocol_version >= 100 else Integer + xyz_type = Double if self.context.protocol_later_eq(100) else Integer for coord in self.x, self.y, self.z: xyz_type.send(coord, packet_buffer) for coord in self.pitch, self.yaw: Angle.send(coord, packet_buffer) Integer.send(self.data, packet_buffer) - if self.context.protocol_version >= 49 or self.data > 0: + if self.context.protocol_later_eq(49) or self.data > 0: for coord in self.velocity_x, self.velocity_y, self.velocity_z: Short.send(coord, packet_buffer) diff --git a/minecraft/networking/packets/keep_alive_packet.py b/minecraft/networking/packets/keep_alive_packet.py index ac6d237..fd8d484 100644 --- a/minecraft/networking/packets/keep_alive_packet.py +++ b/minecraft/networking/packets/keep_alive_packet.py @@ -8,7 +8,7 @@ from minecraft.networking.types import ( class AbstractKeepAlivePacket(Packet): packet_name = "keep alive" get_definition = staticmethod(lambda context: [ - {'keep_alive_id': Long} if context.protocol_version >= 339 + {'keep_alive_id': Long} if context.protocol_later_eq(339) else {'keep_alive_id': VarInt} ]) diff --git a/minecraft/networking/packets/serverbound/login/__init__.py b/minecraft/networking/packets/serverbound/login/__init__.py index 3254d24..dc6fba3 100644 --- a/minecraft/networking/packets/serverbound/login/__init__.py +++ b/minecraft/networking/packets/serverbound/login/__init__.py @@ -11,7 +11,7 @@ def get_packets(context): LoginStartPacket, EncryptionResponsePacket } - if context.protocol_version >= 385: + if context.protocol_later_eq(385): packets |= { PluginResponsePacket } @@ -21,8 +21,8 @@ def get_packets(context): class LoginStartPacket(Packet): @staticmethod def get_id(context): - return 0x00 if context.protocol_version >= 391 else \ - 0x01 if context.protocol_version >= 385 else \ + return 0x00 if context.protocol_later_eq(391) else \ + 0x01 if context.protocol_later_eq(385) else \ 0x00 packet_name = "login start" @@ -33,8 +33,8 @@ class LoginStartPacket(Packet): class EncryptionResponsePacket(Packet): @staticmethod def get_id(context): - return 0x01 if context.protocol_version >= 391 else \ - 0x02 if context.protocol_version >= 385 else \ + return 0x01 if context.protocol_later_eq(391) else \ + 0x02 if context.protocol_later_eq(385) else \ 0x01 packet_name = "encryption response" @@ -50,7 +50,7 @@ class PluginResponsePacket(Packet): @staticmethod def get_id(context): - return 0x02 if context.protocol_version >= 391 else \ + return 0x02 if context.protocol_later_eq(391) else \ 0x00 packet_name = 'login plugin response' diff --git a/minecraft/networking/packets/serverbound/play/__init__.py b/minecraft/networking/packets/serverbound/play/__init__.py index 477cdcd..011100b 100644 --- a/minecraft/networking/packets/serverbound/play/__init__.py +++ b/minecraft/networking/packets/serverbound/play/__init__.py @@ -23,11 +23,11 @@ def get_packets(context): PluginMessagePacket, PlayerBlockPlacementPacket, } - if context.protocol_version >= 69: + if context.protocol_later_eq(69): packets |= { UseItemPacket, } - if context.protocol_version >= 107: + if context.protocol_later_eq(107): packets |= { TeleportConfirmPacket, } @@ -37,33 +37,33 @@ def get_packets(context): class KeepAlivePacket(AbstractKeepAlivePacket): @staticmethod def get_id(context): - return 0x10 if context.protocol_version >= 712 else \ - 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 \ - 0x0B if context.protocol_version >= 336 else \ - 0x0C if context.protocol_version >= 318 else \ - 0x0B if context.protocol_version >= 107 else \ + return 0x10 if context.protocol_later_eq(712) else \ + 0x0F if context.protocol_later_eq(471) else \ + 0x10 if context.protocol_later_eq(464) else \ + 0x0E if context.protocol_later_eq(389) else \ + 0x0C if context.protocol_later_eq(386) else \ + 0x0B if context.protocol_later_eq(345) else \ + 0x0A if context.protocol_later_eq(343) else \ + 0x0B if context.protocol_later_eq(336) else \ + 0x0C if context.protocol_later_eq(318) else \ + 0x0B if context.protocol_later_eq(107) else \ 0x00 class ChatPacket(Packet): @staticmethod def get_id(context): - 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 \ - 0x02 if context.protocol_version >= 107 else \ + return 0x03 if context.protocol_later_eq(464) else \ + 0x02 if context.protocol_later_eq(389) else \ + 0x01 if context.protocol_later_eq(343) else \ + 0x02 if context.protocol_later_eq(336) else \ + 0x03 if context.protocol_later_eq(318) else \ + 0x02 if context.protocol_later_eq(107) else \ 0x01 @staticmethod def get_max_length(context): - return 256 if context.protocol_version >= 306 else \ + return 256 if context.protocol_later_eq(306) else \ 100 @property @@ -79,17 +79,17 @@ class ChatPacket(Packet): class PositionAndLookPacket(Packet): @staticmethod def get_id(context): - return 0x13 if context.protocol_version >= 712 else \ - 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 \ - 0x0E if context.protocol_version >= 336 else \ - 0x0F if context.protocol_version >= 332 else \ - 0x0E if context.protocol_version >= 318 else \ - 0x0D if context.protocol_version >= 107 else \ + return 0x13 if context.protocol_later_eq(712) else \ + 0x12 if context.protocol_later_eq(471) else \ + 0x13 if context.protocol_later_eq(464) else \ + 0x11 if context.protocol_later_eq(389) else \ + 0x0F if context.protocol_later_eq(386) else \ + 0x0E if context.protocol_later_eq(345) else \ + 0x0D if context.protocol_later_eq(343) else \ + 0x0E if context.protocol_later_eq(336) else \ + 0x0F if context.protocol_later_eq(332) else \ + 0x0E if context.protocol_later_eq(318) else \ + 0x0D if context.protocol_later_eq(107) else \ 0x06 packet_name = "position and look" @@ -126,22 +126,22 @@ class TeleportConfirmPacket(Packet): class AnimationPacket(Packet): @staticmethod def get_id(context): - return 0x2C if context.protocol_version >= 738 else \ - 0x2B if context.protocol_version >= 712 else \ - 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 \ - 0x1D if context.protocol_version >= 332 else \ - 0x1C if context.protocol_version >= 318 else \ - 0x1A if context.protocol_version >= 107 else \ + return 0x2C if context.protocol_later_eq(738) else \ + 0x2B if context.protocol_later_eq(712) else \ + 0x2A if context.protocol_later_eq(468) else \ + 0x29 if context.protocol_later_eq(464) else \ + 0x27 if context.protocol_later_eq(389) else \ + 0x25 if context.protocol_later_eq(386) else \ + 0x1D if context.protocol_later_eq(345) else \ + 0x1C if context.protocol_later_eq(343) else \ + 0x1D if context.protocol_later_eq(332) else \ + 0x1C if context.protocol_later_eq(318) else \ + 0x1A if context.protocol_later_eq(107) else \ 0x0A packet_name = "animation" get_definition = staticmethod(lambda context: [ - {'hand': VarInt} if context.protocol_version >= 107 else {}]) + {'hand': VarInt} if context.protocol_later_eq(107) else {}]) Hand = RelativeHand HAND_MAIN, HAND_OFF = Hand.MAIN, Hand.OFF # For backward compatibility. @@ -150,14 +150,14 @@ class AnimationPacket(Packet): class ClientStatusPacket(Packet, Enum): @staticmethod def get_id(context): - 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 \ - 0x03 if context.protocol_version >= 80 else \ - 0x02 if context.protocol_version >= 67 else \ - 0x17 if context.protocol_version >= 49 else \ + return 0x04 if context.protocol_later_eq(464) else \ + 0x03 if context.protocol_later_eq(389) else \ + 0x02 if context.protocol_later_eq(343) else \ + 0x03 if context.protocol_later_eq(336) else \ + 0x04 if context.protocol_later_eq(318) else \ + 0x03 if context.protocol_later_eq(80) else \ + 0x02 if context.protocol_later_eq(67) else \ + 0x17 if context.protocol_later_eq(49) else \ 0x16 packet_name = "client status" @@ -175,13 +175,13 @@ class ClientStatusPacket(Packet, Enum): class PluginMessagePacket(AbstractPluginMessagePacket): @staticmethod def get_id(context): - 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 \ - 0x0A if context.protocol_version >= 317 else \ - 0x09 if context.protocol_version >= 94 else \ + return 0x0B if context.protocol_later_eq(464) else \ + 0x0A if context.protocol_later_eq(389) else \ + 0x09 if context.protocol_later_eq(345) else \ + 0x08 if context.protocol_later_eq(343) else \ + 0x09 if context.protocol_later_eq(336) else \ + 0x0A if context.protocol_later_eq(317) else \ + 0x09 if context.protocol_later_eq(94) else \ 0x17 @@ -201,17 +201,17 @@ class PlayerBlockPlacementPacket(Packet): @staticmethod def get_id(context): - return 0x2E if context.protocol_version >= 738 else \ - 0x2D if context.protocol_version >= 712 else \ - 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 \ - 0x1F if context.protocol_version >= 332 else \ - 0x1E if context.protocol_version >= 318 else \ - 0x1C if context.protocol_version >= 94 else \ + return 0x2E if context.protocol_later_eq(738) else \ + 0x2D if context.protocol_later_eq(712) else \ + 0x2C if context.protocol_later_eq(468) else \ + 0x2B if context.protocol_later_eq(464) else \ + 0x29 if context.protocol_later_eq(389) else \ + 0x27 if context.protocol_later_eq(386) else \ + 0x1F if context.protocol_later_eq(345) else \ + 0x1E if context.protocol_later_eq(343) else \ + 0x1F if context.protocol_later_eq(332) else \ + 0x1E if context.protocol_later_eq(318) else \ + 0x1C if context.protocol_later_eq(94) else \ 0x08 packet_name = 'player block placement' @@ -219,15 +219,15 @@ class PlayerBlockPlacementPacket(Packet): @staticmethod def get_definition(context): return [ - {'hand': VarInt} if context.protocol_version >= 453 else {}, + {'hand': VarInt} if context.protocol_later_eq(453) else {}, {'location': Position}, - {'face': VarInt if context.protocol_version >= 69 else Byte}, - {'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}, + {'face': VarInt if context.protocol_later_eq(69) else Byte}, + {'hand': VarInt} if context.protocol_earlier(453) else {}, + {'x': Float if context.protocol_later_eq(309) else Byte}, + {'y': Float if context.protocol_later_eq(309) else Byte}, + {'z': Float if context.protocol_later_eq(309) else Byte}, ({'inside_block': Boolean} - if context.protocol_version >= 453 else {}), + if context.protocol_later_eq(453) else {}), ] # PlayerBlockPlacementPacket.Hand is an alias for RelativeHand. @@ -240,18 +240,18 @@ class PlayerBlockPlacementPacket(Packet): class UseItemPacket(Packet): @staticmethod def get_id(context): - return 0x2F if context.protocol_version >= 738 else \ - 0x2E if context.protocol_version >= 712 else \ - 0x2D if context.protocol_version >= 468 else \ - 0x2C if context.protocol_version >= 464 else \ - 0x2A if context.protocol_version >= 389 else \ - 0x28 if context.protocol_version >= 386 else \ - 0x20 if context.protocol_version >= 345 else \ - 0x1F if context.protocol_version >= 343 else \ - 0x20 if context.protocol_version >= 332 else \ - 0x1F if context.protocol_version >= 318 else \ - 0x1D if context.protocol_version >= 94 else \ - 0x1A if context.protocol_version >= 70 else \ + return 0x2F if context.protocol_later_eq(738) else \ + 0x2E if context.protocol_later_eq(712) else \ + 0x2D if context.protocol_later_eq(468) else \ + 0x2C if context.protocol_later_eq(464) else \ + 0x2A if context.protocol_later_eq(389) else \ + 0x28 if context.protocol_later_eq(386) else \ + 0x20 if context.protocol_later_eq(345) else \ + 0x1F if context.protocol_later_eq(343) else \ + 0x20 if context.protocol_later_eq(332) else \ + 0x1F if context.protocol_later_eq(318) else \ + 0x1D if context.protocol_later_eq(94) else \ + 0x1A if context.protocol_later_eq(70) else \ 0x08 packet_name = "use item" diff --git a/minecraft/networking/packets/serverbound/play/client_settings_packet.py b/minecraft/networking/packets/serverbound/play/client_settings_packet.py index f5e84e7..a826f09 100644 --- a/minecraft/networking/packets/serverbound/play/client_settings_packet.py +++ b/minecraft/networking/packets/serverbound/play/client_settings_packet.py @@ -8,12 +8,12 @@ from minecraft.networking.types import ( class ClientSettingsPacket(Packet): @staticmethod def get_id(context): - 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 \ - 0x04 if context.protocol_version >= 94 else \ + return 0x05 if context.protocol_later_eq(464) else \ + 0x04 if context.protocol_later_eq(389) else \ + 0x03 if context.protocol_later_eq(343) else \ + 0x04 if context.protocol_later_eq(336) else \ + 0x05 if context.protocol_later_eq(318) else \ + 0x04 if context.protocol_later_eq(94) else \ 0x15 packet_name = 'client settings' @@ -21,10 +21,10 @@ class ClientSettingsPacket(Packet): get_definition = staticmethod(lambda context: [ {'locale': String}, {'view_distance': Byte}, - {'chat_mode': VarInt if context.protocol_version > 47 else Byte}, + {'chat_mode': VarInt if context.protocol_later(47) else Byte}, {'chat_colors': Boolean}, {'displayed_skin_parts': UnsignedByte}, - {'main_hand': VarInt} if context.protocol_version > 49 else {}]) + {'main_hand': VarInt} if context.protocol_later(49) else {}]) field_enum = classmethod( lambda cls, field, context: { diff --git a/minecraft/networking/types/basic.py b/minecraft/networking/types/basic.py index 0a02ecd..52c4f27 100644 --- a/minecraft/networking/types/basic.py +++ b/minecraft/networking/types/basic.py @@ -314,7 +314,7 @@ class Position(Type, Vector): location = UnsignedLong.read(file_object) x = int(location >> 38) # 26 most significant bits - if context.protocol_version >= 443: + if context.protocol_later_eq(443): z = int((location >> 12) & 0x3FFFFFF) # 26 intermediate bits y = int(location & 0xFFF) # 12 least signficant bits else: @@ -337,7 +337,7 @@ class Position(Type, Vector): # 'position' can be either a tuple or Position object. x, y, z = position value = ((x & 0x3FFFFFF) << 38 | (z & 0x3FFFFFF) << 12 | (y & 0xFFF) - if context.protocol_version >= 443 else + if context.protocol_later_eq(443) else (x & 0x3FFFFFF) << 38 | (y & 0xFFF) << 26 | (z & 0x3FFFFFF)) UnsignedLong.send(value, socket) diff --git a/minecraft/networking/types/utility.py b/minecraft/networking/types/utility.py index bf3fa04..ac3cb83 100644 --- a/minecraft/networking/types/utility.py +++ b/minecraft/networking/types/utility.py @@ -1,16 +1,12 @@ """Minecraft data types that are used by packets, but don't have a specific network representation. """ -import types - from collections import namedtuple -from itertools import chain - -__all__ = ( - 'Vector', 'MutableRecord', 'Direction', 'PositionAndLook', 'descriptor', - 'overridable_descriptor', 'overridable_property', 'attribute_alias', - 'multi_attribute_alias', 'attribute_transform', +# These aliases are retained for backward compatibility +from minecraft.utility import ( # noqa: F401 + descriptor, overridable_descriptor, overridable_property, attribute_alias, + multi_attribute_alias, attribute_transform, class_and_instancemethod, ) @@ -92,161 +88,6 @@ class MutableRecord(object): yield slot -def attribute_transform(name, from_orig, to_orig): - """An attribute descriptor that provides a view of a different attribute - with a given name via a given transformation and its given inverse.""" - return property( - fget=(lambda self: from_orig(getattr(self, name))), - fset=(lambda self, value: setattr(self, name, to_orig(value))), - fdel=(lambda self: delattr(self, name))) - - -def attribute_alias(name): - """An attribute descriptor that redirects access to a different attribute - with a given name. - """ - return attribute_transform(name, lambda x: x, lambda x: x) - - -def multi_attribute_alias(container, *arg_names, **kwd_names): - """A descriptor for an attribute whose value is a container of a given type - with several fields, each of which is aliased to a different attribute - of the parent object. - - The 'n'th name in 'arg_names' is the parent attribute that will be - aliased to the field of 'container' settable by the 'n'th positional - argument to its constructor, and accessible as its 'n'th iterable - element. - - As a special case, 'tuple' may be given as the 'container' when there - are positional arguments, and (even though the tuple constructor does - not take positional arguments), the arguments will be aliased to the - corresponding positions in a tuple. - - The name in 'kwd_names' mapped to by the key 'k' is the parent attribute - that will be aliased to the field of 'container' settable by the keyword - argument 'k' to its constructor, and accessible as its 'k' attribute. - """ - if container is tuple: - container = lambda *args: args # noqa: E731 - - @property - def alias(self): - return container( - *(getattr(self, name) for name in arg_names), - **{kwd: getattr(self, name) for (kwd, name) in kwd_names.items()}) - - @alias.setter - def alias(self, values): - if arg_names: - for name, value in zip(arg_names, values): - setattr(self, name, value) - for kwd, name in kwd_names.items(): - setattr(self, name, getattr(values, kwd)) - - @alias.deleter - def alias(self): - for name in chain(arg_names, kwd_names.values()): - delattr(self, name) - - return alias - - -class overridable_descriptor: - """As 'descriptor' (defined below), except that only a getter can be - defined, and the resulting descriptor has no '__set__' or '__delete__' - methods defined; hence, attributes defined via this class can be - overridden by attributes of instances of the class in which it occurs. - """ - __slots__ = '_fget', - - def __init__(self, fget=None): - self._fget = fget if fget is not None else self._default_get - - def getter(self, fget): - self._fget = fget - return self - - @staticmethod - def _default_get(instance, owner): - raise AttributeError('unreadable attribute') - - def __get__(self, instance, owner): - return self._fget(self, instance, owner) - - -class overridable_property(overridable_descriptor): - """As the builtin 'property' decorator of Python, except that only - a getter is defined and the resulting descriptor is a non-data - descriptor, overridable by attributes of instances of the class - in which the property occurs. See also 'overridable_descriptor' above. - """ - def __get__(self, instance, _owner): - return self._fget(instance) - - -class descriptor(overridable_descriptor): - """Behaves identically to the builtin 'property' decorator 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. - - Since an instance of this class always havs '__set__' and '__delete__' - defined, it is a "data descriptor", so its binding behaviour cannot be - overridden in instances of the class in which it occurs. See - https://docs.python.org/3/reference/datamodel.html#descriptor-invocation - for more information. See also 'overridable_descriptor' above. - """ - __slots__ = '_fset', '_fdel' - - def __init__(self, fget=None, fset=None, fdel=None): - super(descriptor, self).__init__(fget=fget) - 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 setter(self, fset): - self._fset = fset - return self - - def deleter(self, fdel): - self._fdel = fdel - return self - - @staticmethod - def _default_set(instance, value): - raise AttributeError("can't set attribute") - - @staticmethod - def _default_del(instance): - raise AttributeError("can't delete attribute") - - def __set__(self, instance, value): - return self._fset(self, instance, value) - - def __delete__(self, instance): - return self._fdel(self, instance) - - -class class_and_instancemethod: - """ A decorator for functions defined in a class namespace which are to be - accessed as both class and instance methods: retrieving the method from - a class will return a bound class method (like the built-in - 'classmethod' decorator), but retrieving the method from an instance - will return a bound instance method (as if the function were not - decorated). Therefore, the first argument of the decorated function may - be either a class or an instance, depending on how it was called. - """ - - __slots__ = '_func', - - def __init__(self, func): - self._func = func - - def __get__(self, inst, owner=None): - bind_to = owner if inst is None else inst - return types.MethodType(self._func, bind_to) - - Direction = namedtuple('Direction', ('yaw', 'pitch')) diff --git a/minecraft/utility.py b/minecraft/utility.py new file mode 100644 index 0000000..2ab8d1d --- /dev/null +++ b/minecraft/utility.py @@ -0,0 +1,175 @@ +""" Miscellaneous general utilities. +""" +import types +from itertools import chain + +from . import PROTOCOL_VERSION_INDICES + + +def protocol_earlier(pv1, pv2): + """ Returns True if protocol version 'pv1' was published before 'pv2', + or else returns False. + """ + return PROTOCOL_VERSION_INDICES[pv1] < PROTOCOL_VERSION_INDICES[pv2] + + +def protocol_earlier_eq(pv1, pv2): + """ Returns True if protocol versions 'pv1' and 'pv2' are the same or if + 'pv1' was published before 'pv2', or else returns False. + """ + return PROTOCOL_VERSION_INDICES[pv1] <= PROTOCOL_VERSION_INDICES[pv2] + + +def attribute_transform(name, from_orig, to_orig): + """An attribute descriptor that provides a view of a different attribute + with a given name via a given transformation and its given inverse.""" + return property( + fget=(lambda self: from_orig(getattr(self, name))), + fset=(lambda self, value: setattr(self, name, to_orig(value))), + fdel=(lambda self: delattr(self, name))) + + +def attribute_alias(name): + """An attribute descriptor that redirects access to a different attribute + with a given name. + """ + return attribute_transform(name, lambda x: x, lambda x: x) + + +def multi_attribute_alias(container, *arg_names, **kwd_names): + """A descriptor for an attribute whose value is a container of a given type + with several fields, each of which is aliased to a different attribute + of the parent object. + + The 'n'th name in 'arg_names' is the parent attribute that will be + aliased to the field of 'container' settable by the 'n'th positional + argument to its constructor, and accessible as its 'n'th iterable + element. + + As a special case, 'tuple' may be given as the 'container' when there + are positional arguments, and (even though the tuple constructor does + not take positional arguments), the arguments will be aliased to the + corresponding positions in a tuple. + + The name in 'kwd_names' mapped to by the key 'k' is the parent attribute + that will be aliased to the field of 'container' settable by the keyword + argument 'k' to its constructor, and accessible as its 'k' attribute. + """ + if container is tuple: + container = lambda *args: args # noqa: E731 + + @property + def alias(self): + return container( + *(getattr(self, name) for name in arg_names), + **{kwd: getattr(self, name) for (kwd, name) in kwd_names.items()}) + + @alias.setter + def alias(self, values): + if arg_names: + for name, value in zip(arg_names, values): + setattr(self, name, value) + for kwd, name in kwd_names.items(): + setattr(self, name, getattr(values, kwd)) + + @alias.deleter + def alias(self): + for name in chain(arg_names, kwd_names.values()): + delattr(self, name) + + return alias + + +class overridable_descriptor: + """As 'descriptor' (defined below), except that only a getter can be + defined, and the resulting descriptor has no '__set__' or '__delete__' + methods defined; hence, attributes defined via this class can be + overridden by attributes of instances of the class in which it occurs. + """ + __slots__ = '_fget', + + def __init__(self, fget=None): + self._fget = fget if fget is not None else self._default_get + + def getter(self, fget): + self._fget = fget + return self + + @staticmethod + def _default_get(instance, owner): + raise AttributeError('unreadable attribute') + + def __get__(self, instance, owner): + return self._fget(self, instance, owner) + + +class overridable_property(overridable_descriptor): + """As the builtin 'property' decorator of Python, except that only + a getter is defined and the resulting descriptor is a non-data + descriptor, overridable by attributes of instances of the class + in which the property occurs. See also 'overridable_descriptor' above. + """ + def __get__(self, instance, _owner): + return self._fget(instance) + + +class descriptor(overridable_descriptor): + """Behaves identically to the builtin 'property' decorator 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. + + Since an instance of this class always havs '__set__' and '__delete__' + defined, it is a "data descriptor", so its binding behaviour cannot be + overridden in instances of the class in which it occurs. See + https://docs.python.org/3/reference/datamodel.html#descriptor-invocation + for more information. See also 'overridable_descriptor' above. + """ + __slots__ = '_fset', '_fdel' + + def __init__(self, fget=None, fset=None, fdel=None): + super(descriptor, self).__init__(fget=fget) + 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 setter(self, fset): + self._fset = fset + return self + + def deleter(self, fdel): + self._fdel = fdel + return self + + @staticmethod + def _default_set(instance, value): + raise AttributeError("can't set attribute") + + @staticmethod + def _default_del(instance): + raise AttributeError("can't delete attribute") + + def __set__(self, instance, value): + return self._fset(self, instance, value) + + def __delete__(self, instance): + return self._fdel(self, instance) + + +class class_and_instancemethod: + """ A decorator for functions defined in a class namespace which are to be + accessed as both class and instance methods: retrieving the method from + a class will return a bound class method (like the built-in + 'classmethod' decorator), but retrieving the method from an instance + will return a bound instance method (as if the function were not + decorated). Therefore, the first argument of the decorated function may + be either a class or an instance, depending on how it was called. + """ + + __slots__ = '_func', + + def __init__(self, func): + self._func = func + + def __get__(self, inst, owner=None): + bind_to = owner if inst is None else inst + return types.MethodType(self._func, bind_to) diff --git a/tests/fake_server.py b/tests/fake_server.py index 2bc24ec..9d5251b 100644 --- a/tests/fake_server.py +++ b/tests/fake_server.py @@ -24,9 +24,6 @@ import hashlib import uuid -VERSIONS = sorted(SUPPORTED_MINECRAFT_VERSIONS.items(), key=lambda i: i[1]) -VERSIONS = [v for (v, p) in VERSIONS] - THREAD_TIMEOUT_S = 2 @@ -108,7 +105,7 @@ class FakeClientHandler(object): level_type='default', reduced_debug_info=False, render_distance=9, respawn_screen=False, is_debug=False, is_flat=False) - if self.server.context.protocol_version >= 748: + if self.server.context.protocol_later_eq(748): packet.dimension = pynbt.TAG_Compound({ 'natural': pynbt.TAG_Byte(1), 'effects': pynbt.TAG_String('minecraft:overworld'), @@ -134,7 +131,7 @@ class FakeClientHandler(object): ]), }), }, '') - elif self.server.context.protocol_version >= 718: + elif self.server.context.protocol_later_eq(718): packet.dimension = 'minecraft:overworld' else: packet.dimension = types.Dimension.OVERWORLD @@ -232,13 +229,13 @@ class FakeClientHandler(object): # Prepare to transition from handshaking to play state (via login), # using the given serverbound HandShakePacket to perform play-specific # processing. - if packet.protocol_version == self.server.context.protocol_version: + if self.server.context.protocol_version == packet.protocol_version: return self._run_login() - if packet.protocol_version < self.server.context.protocol_version: - msg = 'Outdated client! Please use %s' \ + elif self.server.context.protocol_earlier(packet.protocol_version): + msg = "Outdated server! I'm still on %s" \ % self.server.minecraft_version else: - msg = "Outdated server! I'm still on %s" \ + msg = 'Outdated client! Please use %s' \ % self.server.minecraft_version self.handle_login_server_disconnect(msg) @@ -372,7 +369,7 @@ class FakeServer(object): client_handler_type=FakeClientHandler, private_key=None, public_key_bytes=None, test_case=None): if minecraft_version is None: - minecraft_version = VERSIONS[-1][0] + minecraft_version = list(SUPPORTED_MINECRAFT_VERSIONS.keys())[-1] if isinstance(minecraft_version, Integral): proto = minecraft_version @@ -458,8 +455,9 @@ class _FakeServerTest(unittest.TestCase): must raise a 'FakeServerTestSuccess' exception. """ - server_version = VERSIONS[-1] + server_version = None # The Minecraft version ID that the server will support. + # If None, the latest supported version will be used. client_versions = None # The set of Minecraft version IDs or protocol version numbers that the diff --git a/tests/test_backward_compatible.py b/tests/test_backward_compatible.py index c9cc66c..d929eac 100644 --- a/tests/test_backward_compatible.py +++ b/tests/test_backward_compatible.py @@ -1,6 +1,7 @@ import unittest from minecraft import SUPPORTED_PROTOCOL_VERSIONS +from minecraft import utility from minecraft.networking.connection import ConnectionContext from minecraft.networking import packets from minecraft.networking import types @@ -87,6 +88,12 @@ class LegacyTypesTest(unittest.TestCase): self.assertIsInstance(types.FixedPointInteger, types.FixedPoint) self.assertEqual(types.FixedPointInteger.denominator, 32) + for attr in ('descriptor', 'overridable_descriptor', + 'overridable_property', 'attribute_alias', + 'multi_attribute_alias', 'attribute_transform', + 'class_and_instancemethod'): + self.assertEqual(getattr(types, attr), getattr(utility, attr)) + class ClassMemberAliasesTest(unittest.TestCase): def test_alias_values(self): diff --git a/tests/test_connection.py b/tests/test_connection.py index 1f52f29..c55a1e4 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1,5 +1,7 @@ -from minecraft import SUPPORTED_MINECRAFT_VERSIONS -from minecraft import SUPPORTED_PROTOCOL_VERSIONS +from minecraft import ( + SUPPORTED_MINECRAFT_VERSIONS, SUPPORTED_PROTOCOL_VERSIONS, + PROTOCOL_VERSION_INDICES, +) from minecraft.networking.packets import clientbound, serverbound from minecraft.networking.connection import Connection from minecraft.exceptions import ( @@ -119,26 +121,22 @@ class ConnectCompressionHighTest(ConnectTest): class AllowedVersionsTest(fake_server._FakeServerTest): - versions = sorted(SUPPORTED_MINECRAFT_VERSIONS.items(), key=lambda p: p[1]) - versions = dict((versions[0], versions[len(versions)//2], versions[-1])) + versions = list(SUPPORTED_MINECRAFT_VERSIONS.items()) + test_indices = (0, len(versions) // 2, len(versions) - 1) client_handler_type = ConnectTest.client_handler_type def test_with_version_names(self): - for version, proto in AllowedVersionsTest.versions.items(): - client_versions = { - v for (v, p) in SUPPORTED_MINECRAFT_VERSIONS.items() - if p <= proto} + for index in self.test_indices: self._test_connect( - server_version=version, client_versions=client_versions) + server_version=self.versions[index][0], + client_versions={v[0] for v in self.versions[:index+1]}) def test_with_protocol_numbers(self): - for version, proto in AllowedVersionsTest.versions.items(): - client_versions = { - p for (v, p) in SUPPORTED_MINECRAFT_VERSIONS.items() - if p <= proto} + for index in self.test_indices: self._test_connect( - server_version=version, client_versions=client_versions) + server_version=self.versions[index][0], + client_versions={v[1] for v in self.versions[:index+1]}) class LoginDisconnectTest(fake_server._FakeServerTest): @@ -363,12 +361,22 @@ class HandleExceptionTest(ConnectTest): class VersionNegotiationEdgeCases(fake_server._FakeServerTest): - lowest_version = min(SUPPORTED_PROTOCOL_VERSIONS) - highest_version = max(SUPPORTED_PROTOCOL_VERSIONS) - impossible_version = highest_version + 1 + earliest_version = SUPPORTED_PROTOCOL_VERSIONS[0] + latest_version = SUPPORTED_PROTOCOL_VERSIONS[-1] + + fake_version = max(PROTOCOL_VERSION_INDICES.keys()) + 1 + fake_version_index = max(PROTOCOL_VERSION_INDICES.values()) + 1 + + def setUp(self): + PROTOCOL_VERSION_INDICES[self.fake_version] = self.fake_version_index + super(VersionNegotiationEdgeCases, self).setUp() + + def tearDown(self): + super(VersionNegotiationEdgeCases, self).tearDown() + del PROTOCOL_VERSION_INDICES[self.fake_version] def test_client_protocol_unsupported(self): - self._test_client_protocol(version=self.impossible_version) + self._test_client_protocol(version=self.fake_version) def test_client_protocol_unknown(self): self._test_client_protocol(version='surprise me!') @@ -383,21 +391,21 @@ class VersionNegotiationEdgeCases(fake_server._FakeServerTest): def test_server_protocol_unsupported(self, client_versions=None): with self.assertRaisesRegexp(VersionMismatch, 'not supported'): self._test_connect(client_versions=client_versions, - server_version=self.impossible_version) + server_version=self.fake_version) def test_server_protocol_unsupported_direct(self): - self.test_server_protocol_unsupported({self.highest_version}) + self.test_server_protocol_unsupported({self.latest_version}) def test_server_protocol_disallowed(self, client_versions=None): if client_versions is None: client_versions = set(SUPPORTED_PROTOCOL_VERSIONS) \ - - {self.highest_version} + - {self.latest_version} with self.assertRaisesRegexp(VersionMismatch, 'not allowed'): - self._test_connect(client_versions={self.lowest_version}, - server_version=self.highest_version) + self._test_connect(client_versions={self.earliest_version}, + server_version=self.latest_version) def test_server_protocol_disallowed_direct(self): - self.test_server_protocol_disallowed({self.lowest_version}) + self.test_server_protocol_disallowed({self.earliest_version}) def test_default_protocol_version(self, status_response=None): if status_response is None: @@ -414,10 +422,10 @@ class VersionNegotiationEdgeCases(fake_server._FakeServerTest): raise fake_server.FakeServerDisconnect('Test complete.') def make_connection(*args, **kwds): - kwds['initial_version'] = self.lowest_version + kwds['initial_version'] = self.earliest_version return Connection(*args, **kwds) - self._test_connect(server_version=self.lowest_version, + self._test_connect(server_version=self.earliest_version, client_handler_type=ClientHandler, connection_type=make_connection) @@ -436,9 +444,9 @@ class VersionNegotiationEdgeCases(fake_server._FakeServerTest): raise fake_server.FakeServerDisconnect('Test complete.') def make_connection(*args, **kwds): - kwds['initial_version'] = self.lowest_version + kwds['initial_version'] = self.earliest_version return Connection(*args, **kwds) - self._test_connect(server_version=self.lowest_version, + self._test_connect(server_version=self.earliest_version, client_handler_type=ClientHandler, connection_type=make_connection) diff --git a/tests/test_packets.py b/tests/test_packets.py index 57efeb9..44b775c 100644 --- a/tests/test_packets.py +++ b/tests/test_packets.py @@ -209,7 +209,7 @@ class TestReadWritePackets(unittest.TestCase): context.protocol_version = protocol_version packet = clientbound.play.MultiBlockChangePacket(context) - if protocol_version >= 741: + if context.protocol_later_eq(741): packet.chunk_section_pos = Vector(167, 17, 33) packet.invert_trust_edges = False else: @@ -239,8 +239,9 @@ class TestReadWritePackets(unittest.TestCase): 'type_id', context) pos_look = PositionAndLook( - position=(Vector(68.0, 38.0, 76.0) if protocol_version >= 100 - else Vector(68, 38, 76)), + position=(Vector(68.0, 38.0, 76.0) + if context.protocol_later_eq(100) else + Vector(68, 38, 76)), yaw=263.494, pitch=180) velocity = Vector(21, 55, 41) entity_id, type_name, type_id = 49846, 'EGG', EntityType.EGG @@ -252,7 +253,7 @@ class TestReadWritePackets(unittest.TestCase): velocity_x=velocity.x, velocity_y=velocity.y, velocity_z=velocity.z, entity_id=entity_id, type_id=type_id, data=1) - if protocol_version >= 49: + if context.protocol_later_eq(49): object_uuid = 'd9568851-85bc-4a10-8d6a-261d130626fa' packet.object_uuid = object_uuid self.assertEqual(packet.objectUUID, object_uuid) @@ -267,12 +268,12 @@ class TestReadWritePackets(unittest.TestCase): "object_uuid='d9568851-85bc-4a10-8d6a-261d130626fa', " "type_id=EGG, x=68.0, y=38.0, z=76.0, pitch=180, yaw=263.494, " "data=1, velocity_x=21, velocity_y=55, velocity_z=41)" - % packet.id if protocol_version >= 100 else + % packet.id if context.protocol_later_eq(100) else "0x%02X SpawnObjectPacket(entity_id=49846, " "object_uuid='d9568851-85bc-4a10-8d6a-261d130626fa', " "type_id=EGG, x=68, y=38, z=76, pitch=180, yaw=263.494, " "data=1, velocity_x=21, velocity_y=55, velocity_z=41)" - % packet.id if protocol_version >= 49 else + % packet.id if context.protocol_later_eq(49) else "0x%02X SpawnObjectPacket(entity_id=49846, type_id=EGG, " "x=68, y=38, z=76, pitch=180, yaw=263.494, data=1, " "velocity_x=21, velocity_y=55, velocity_z=41)" % packet.id @@ -282,7 +283,7 @@ class TestReadWritePackets(unittest.TestCase): context=context, position_and_look=pos_look, velocity=velocity, type=type_name, entity_id=entity_id, data=1) - if protocol_version >= 49: + if context.protocol_later_eq(49): packet2.object_uuid = object_uuid self.assertEqual(packet.__dict__, packet2.__dict__) @@ -290,7 +291,7 @@ class TestReadWritePackets(unittest.TestCase): self.assertEqual(packet.position, packet2.position) packet2.data = 0 - if protocol_version < 49: + if context.protocol_earlier(49): del packet2.velocity self._test_read_write_packet(packet, context, yaw=360/256, pitch=360/256) @@ -304,11 +305,11 @@ class TestReadWritePackets(unittest.TestCase): packet = clientbound.play.SoundEffectPacket( sound_id=545, effect_position=Vector(0.125, 300.0, 50.5), volume=0.75) - if protocol_version >= 201: + if context.protocol_later_eq(201): packet.pitch = struct.unpack('f', struct.pack('f', 1.5))[0] else: packet.pitch = int(1.5 / 63.5) * 63.5 - if context.protocol_version >= 95: + if context.protocol_later_eq(95): packet.sound_category = \ clientbound.play.SoundEffectPacket.SoundCategory.NEUTRAL @@ -321,19 +322,20 @@ class TestReadWritePackets(unittest.TestCase): packet = clientbound.play.FacePlayerPacket(context) packet.target = 1.0, -2.0, 3.5 packet.entity_id = None - if protocol_version >= 353: + if context.protocol_later_eq(353): packet.origin = OriginPoint.EYES self.assertEqual( str(packet), "0x%02X FacePlayerPacket(origin=EYES, x=1.0, y=-2.0, z=3.5, " - "entity_id=None)" % packet.id if protocol_version >= 353 else + "entity_id=None)" % packet.id + if context.protocol_later_eq(353) else "0x%02X FacePlayerPacket(entity_id=None, x=1.0, y=-2.0, z=3.5)" % packet.id ) self._test_read_write_packet(packet, context) packet.entity_id = 123 - if protocol_version >= 353: + if context.protocol_later_eq(353): packet.entity_origin = OriginPoint.FEET else: del packet.target @@ -341,7 +343,7 @@ class TestReadWritePackets(unittest.TestCase): str(packet), "0x%02X FacePlayerPacket(origin=EYES, x=1.0, y=-2.0, z=3.5, " "entity_id=123, entity_origin=FEET)" % packet.id - if protocol_version >= 353 else + if context.protocol_later_eq(353) else "0x%02X FacePlayerPacket(entity_id=123)" % packet.id ) self._test_read_write_packet(packet, context) diff --git a/tests/test_packets_with_logic.py b/tests/test_packets_with_logic.py index e9a202e..c10a74b 100644 --- a/tests/test_packets_with_logic.py +++ b/tests/test_packets_with_logic.py @@ -55,7 +55,7 @@ class MapPacketTest(unittest.TestCase): packet.is_tracking_position = True packet.is_locked = False packet.icons = [] - d_name = u'Marshmallow' if context.protocol_version >= 364 else None + d_name = u'Marshmallow' if context.protocol_later_eq(364) else None packet.icons.append(MapPacket.MapIcon( type=2, direction=2, location=(1, 1), display_name=d_name )) diff --git a/tests/test_reactors.py b/tests/test_reactors.py index 9d0de52..206a35b 100644 --- a/tests/test_reactors.py +++ b/tests/test_reactors.py @@ -11,7 +11,7 @@ from minecraft.networking.connection import ( from minecraft.networking.packets import clientbound -max_proto_ver = max(SUPPORTED_PROTOCOL_VERSIONS) +latest_proto = SUPPORTED_PROTOCOL_VERSIONS[-1] class LoginReactorTest(unittest.TestCase): @@ -19,7 +19,7 @@ class LoginReactorTest(unittest.TestCase): @mock.patch('minecraft.networking.connection.encryption') def test_encryption_online_server(self, encrypt): connection = mock.MagicMock() - connection.context = ConnectionContext(protocol_version=max_proto_ver) + connection.context = ConnectionContext(protocol_version=latest_proto) reactor = LoginReactor(connection) packet = clientbound.login.EncryptionRequestPacket() @@ -43,7 +43,7 @@ class LoginReactorTest(unittest.TestCase): @mock.patch('minecraft.networking.connection.encryption') def test_encryption_offline_server(self, encrypt): connection = mock.MagicMock() - connection.context = ConnectionContext(protocol_version=max_proto_ver) + connection.context = ConnectionContext(protocol_version=latest_proto) reactor = LoginReactor(connection) packet = clientbound.login.EncryptionRequestPacket() diff --git a/tox.ini b/tox.ini index a465d4b..488032d 100644 --- a/tox.ini +++ b/tox.ini @@ -50,7 +50,8 @@ deps = [flake8] per-file-ignores = - */clientbound/play/spawn_object_packet.py:E221,E222,E271,E272 + */clientbound/play/spawn_object_packet.py:E221,E222,E271,E272,E201 + minecraft/networking/packets/__init__.py:F401 [testenv:pylint-errors] basepython = python3.8