Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
from minecraft import (
|
|
|
|
SUPPORTED_MINECRAFT_VERSIONS, SUPPORTED_PROTOCOL_VERSIONS,
|
|
|
|
PROTOCOL_VERSION_INDICES,
|
|
|
|
)
|
2017-08-22 18:50:16 +02:00
|
|
|
from minecraft.networking.packets import clientbound, serverbound
|
2018-07-19 02:59:48 +02:00
|
|
|
from minecraft.networking.connection import Connection
|
2018-05-29 02:14:46 +02:00
|
|
|
from minecraft.exceptions import (
|
2018-07-19 02:59:48 +02:00
|
|
|
VersionMismatch, LoginDisconnect, InvalidState, IgnorePacket
|
2018-05-29 02:14:46 +02:00
|
|
|
)
|
2017-08-22 18:50:16 +02:00
|
|
|
|
|
|
|
from . import fake_server
|
2016-06-18 19:22:18 +02:00
|
|
|
|
2018-05-27 08:40:13 +02:00
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
import io
|
|
|
|
|
2016-06-18 19:22:18 +02:00
|
|
|
|
2017-08-22 15:06:17 +02:00
|
|
|
class ConnectTest(fake_server._FakeServerTest):
|
|
|
|
def test_connect(self):
|
2016-11-20 06:03:23 +01:00
|
|
|
self._test_connect()
|
|
|
|
|
2017-08-22 18:50:16 +02:00
|
|
|
class client_handler_type(fake_server.FakeClientHandler):
|
|
|
|
def handle_play_start(self):
|
|
|
|
super(ConnectTest.client_handler_type, self).handle_play_start()
|
2017-08-22 19:12:51 +02:00
|
|
|
self.write_packet(clientbound.play.KeepAlivePacket(
|
|
|
|
keep_alive_id=1223334444))
|
|
|
|
|
|
|
|
def handle_play_packet(self, packet):
|
|
|
|
super(ConnectTest.client_handler_type, self) \
|
|
|
|
.handle_play_packet(packet)
|
|
|
|
if isinstance(packet, serverbound.play.KeepAlivePacket):
|
|
|
|
assert packet.keep_alive_id == 1223334444
|
|
|
|
raise fake_server.FakeServerDisconnect
|
2017-08-22 18:50:16 +02:00
|
|
|
|
2017-08-22 15:06:17 +02:00
|
|
|
|
2018-10-12 17:47:55 +02:00
|
|
|
class ReconnectTest(ConnectTest):
|
|
|
|
phase = 0
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
def handle_login_disconnect(packet):
|
|
|
|
if 'Please reconnect' in packet.json_data:
|
|
|
|
# Override the default behaviour of raising a fatal exception.
|
|
|
|
client.disconnect()
|
|
|
|
client.connect()
|
|
|
|
raise IgnorePacket
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_login_disconnect, clientbound.login.DisconnectPacket,
|
|
|
|
early=True)
|
|
|
|
|
|
|
|
def handle_play_disconnect(packet):
|
|
|
|
if 'Please reconnect' in packet.json_data:
|
|
|
|
client.connect()
|
|
|
|
elif 'Test successful' in packet.json_data:
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_play_disconnect, clientbound.play.DisconnectPacket)
|
|
|
|
|
|
|
|
client.connect()
|
|
|
|
|
|
|
|
class client_handler_type(fake_server.FakeClientHandler):
|
|
|
|
def handle_login(self, packet):
|
|
|
|
if self.server.test_case.phase == 0:
|
|
|
|
self.server.test_case.phase = 1
|
|
|
|
raise fake_server.FakeServerDisconnect('Please reconnect (0).')
|
|
|
|
super(ReconnectTest.client_handler_type, self).handle_login(packet)
|
|
|
|
|
|
|
|
def handle_play_start(self):
|
|
|
|
if self.server.test_case.phase == 1:
|
|
|
|
self.server.test_case.phase = 2
|
|
|
|
raise fake_server.FakeServerDisconnect('Please reconnect (1).')
|
|
|
|
else:
|
|
|
|
assert self.server.test_case.phase == 2
|
|
|
|
raise fake_server.FakeServerDisconnect('Test successful (2).')
|
|
|
|
|
|
|
|
|
2017-08-22 15:06:17 +02:00
|
|
|
class PingTest(ConnectTest):
|
|
|
|
def _start_client(self, client):
|
2016-11-20 06:03:23 +01:00
|
|
|
def handle_ping(latency_ms):
|
|
|
|
assert 0 <= latency_ms < 60000
|
2017-08-22 15:06:17 +02:00
|
|
|
raise fake_server.FakeServerTestSuccess
|
2016-11-20 06:03:23 +01:00
|
|
|
client.status(handle_status=False, handle_ping=handle_ping)
|
|
|
|
|
|
|
|
|
2018-05-27 08:40:13 +02:00
|
|
|
class StatusTest(ConnectTest):
|
|
|
|
def _start_client(self, client):
|
|
|
|
def handle_status(status_dict):
|
|
|
|
assert status_dict['description'] == {'text': 'FakeServer'}
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
|
|
|
client.status(handle_status=handle_status, handle_ping=False)
|
|
|
|
|
|
|
|
|
|
|
|
class DefaultStatusTest(ConnectTest):
|
|
|
|
def setUp(self):
|
|
|
|
class FakeStdOut(io.BytesIO):
|
|
|
|
def write(self, data):
|
2020-08-17 06:41:06 +02:00
|
|
|
if isinstance(data, str):
|
2018-05-27 08:40:13 +02:00
|
|
|
data = data.encode('utf8')
|
|
|
|
super(FakeStdOut, self).write(data)
|
|
|
|
sys.stdout, self.old_stdout = FakeStdOut(), sys.stdout
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
sys.stdout, self.old_stdout = self.old_stdout, None
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
def handle_exit():
|
|
|
|
output = sys.stdout.getvalue()
|
|
|
|
assert re.match(b'{.*}\\nPing: \\d+ ms\\n$', output), \
|
|
|
|
'Invalid stdout contents: %r.' % output
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
|
|
|
client.handle_exit = handle_exit
|
|
|
|
|
|
|
|
client.status(handle_status=None, handle_ping=None)
|
|
|
|
|
|
|
|
|
2017-08-22 15:06:17 +02:00
|
|
|
class ConnectCompressionLowTest(ConnectTest):
|
|
|
|
compression_threshold = 0
|
2016-11-20 06:03:23 +01:00
|
|
|
|
2015-04-03 19:04:45 +02:00
|
|
|
|
2017-08-22 15:06:17 +02:00
|
|
|
class ConnectCompressionHighTest(ConnectTest):
|
|
|
|
compression_threshold = 256
|
2015-04-03 19:04:45 +02:00
|
|
|
|
|
|
|
|
2017-08-22 15:06:17 +02:00
|
|
|
class AllowedVersionsTest(fake_server._FakeServerTest):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
versions = list(SUPPORTED_MINECRAFT_VERSIONS.items())
|
|
|
|
test_indices = (0, len(versions) // 2, len(versions) - 1)
|
2017-08-22 18:50:16 +02:00
|
|
|
|
|
|
|
client_handler_type = ConnectTest.client_handler_type
|
2017-08-22 15:06:17 +02:00
|
|
|
|
|
|
|
def test_with_version_names(self):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
for index in self.test_indices:
|
2017-08-22 15:06:17 +02:00
|
|
|
self._test_connect(
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
server_version=self.versions[index][0],
|
|
|
|
client_versions={v[0] for v in self.versions[:index+1]})
|
2017-08-22 15:06:17 +02:00
|
|
|
|
|
|
|
def test_with_protocol_numbers(self):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
for index in self.test_indices:
|
2017-08-22 15:06:17 +02:00
|
|
|
self._test_connect(
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
server_version=self.versions[index][0],
|
|
|
|
client_versions={v[1] for v in self.versions[:index+1]})
|
2017-08-22 18:50:16 +02:00
|
|
|
|
|
|
|
|
2018-05-29 02:14:46 +02:00
|
|
|
class LoginDisconnectTest(fake_server._FakeServerTest):
|
|
|
|
def test_login_disconnect(self):
|
|
|
|
with self.assertRaisesRegexp(LoginDisconnect, r'You are banned'):
|
|
|
|
self._test_connect()
|
|
|
|
|
|
|
|
class client_handler_type(fake_server.FakeClientHandler):
|
|
|
|
def handle_login(self, login_start_packet):
|
|
|
|
raise fake_server.FakeServerDisconnect('You are banned.')
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectTwiceTest(fake_server._FakeServerTest):
|
|
|
|
def test_connect(self):
|
|
|
|
with self.assertRaisesRegexp(InvalidState, 'existing connection'):
|
|
|
|
self._test_connect()
|
|
|
|
|
|
|
|
class client_handler_type(fake_server.FakeClientHandler):
|
|
|
|
def handle_play_start(self):
|
|
|
|
super(ConnectTwiceTest.client_handler_type, self) \
|
|
|
|
.handle_play_start()
|
|
|
|
raise fake_server.FakeServerDisconnect('Test complete.')
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
client.connect()
|
|
|
|
client.connect()
|
|
|
|
|
|
|
|
|
|
|
|
class ConnectStatusTest(ConnectTwiceTest):
|
|
|
|
def _start_client(self, client):
|
|
|
|
client.connect()
|
|
|
|
client.status()
|
|
|
|
|
|
|
|
|
2018-07-19 02:59:48 +02:00
|
|
|
class LoginPluginTest(fake_server._FakeServerTest):
|
|
|
|
class client_handler_type(fake_server.FakeClientHandler):
|
|
|
|
def handle_login(self, login_start_packet):
|
|
|
|
request = clientbound.login.PluginRequestPacket(
|
|
|
|
message_id=1, channel='pyCraft:tests/fail', data=b'ignored')
|
|
|
|
self.write_packet(request)
|
|
|
|
response = self.read_packet()
|
|
|
|
assert isinstance(response, serverbound.login.PluginResponsePacket)
|
|
|
|
assert response.message_id == request.message_id
|
|
|
|
assert response.successful is False
|
|
|
|
assert response.data is None
|
|
|
|
|
|
|
|
request = clientbound.login.PluginRequestPacket(
|
|
|
|
message_id=2, channel='pyCraft:tests/echo', data=b'hello')
|
|
|
|
self.write_packet(request)
|
|
|
|
response = self.read_packet()
|
|
|
|
assert isinstance(response, serverbound.login.PluginResponsePacket)
|
|
|
|
assert response.message_id == request.message_id
|
|
|
|
assert response.successful is True
|
|
|
|
assert response.data == request.data
|
|
|
|
|
|
|
|
super(LoginPluginTest.client_handler_type, self) \
|
|
|
|
.handle_login(login_start_packet)
|
|
|
|
|
|
|
|
def handle_play_start(self):
|
|
|
|
super(LoginPluginTest.client_handler_type, self) \
|
|
|
|
.handle_play_start()
|
|
|
|
raise fake_server.FakeServerDisconnect
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
def handle_plugin_request(packet):
|
|
|
|
if packet.channel == 'pyCraft:tests/echo':
|
|
|
|
client.write_packet(serverbound.login.PluginResponsePacket(
|
|
|
|
message_id=packet.message_id, data=packet.data))
|
|
|
|
raise IgnorePacket
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_plugin_request, clientbound.login.PluginRequestPacket,
|
|
|
|
early=True)
|
|
|
|
|
|
|
|
super(LoginPluginTest, self)._start_client(client)
|
|
|
|
|
|
|
|
def test_login_plugin_messages(self):
|
|
|
|
self._test_connect()
|
|
|
|
|
|
|
|
|
2017-08-22 18:50:16 +02:00
|
|
|
class EarlyPacketListenerTest(ConnectTest):
|
|
|
|
""" Early packet listeners should be called before ordinary ones, even when
|
|
|
|
the early packet listener is registered afterwards.
|
|
|
|
"""
|
|
|
|
def _start_client(self, client):
|
2019-05-13 19:04:35 +02:00
|
|
|
@client.listener(clientbound.play.JoinGamePacket)
|
2017-08-22 18:50:16 +02:00
|
|
|
def handle_join(packet):
|
|
|
|
assert early_handle_join.called, \
|
|
|
|
'Ordinary listener called before early listener.'
|
|
|
|
handle_join.called = True
|
|
|
|
handle_join.called = False
|
|
|
|
|
2019-05-13 19:04:35 +02:00
|
|
|
@client.listener(clientbound.play.JoinGamePacket, early=True)
|
2017-08-22 18:50:16 +02:00
|
|
|
def early_handle_join(packet):
|
|
|
|
early_handle_join.called = True
|
|
|
|
early_handle_join.called = False
|
|
|
|
|
2019-05-13 19:04:35 +02:00
|
|
|
@client.listener(clientbound.play.DisconnectPacket)
|
2017-08-22 18:50:16 +02:00
|
|
|
def handle_disconnect(packet):
|
|
|
|
assert early_handle_join.called, 'Early listener not called.'
|
|
|
|
assert handle_join.called, 'Ordinary listener not called.'
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
|
|
|
|
|
|
|
client.connect()
|
|
|
|
|
|
|
|
|
|
|
|
class IgnorePacketTest(ConnectTest):
|
|
|
|
""" Raising 'minecraft.networking.connection.IgnorePacket' from within a
|
|
|
|
packet listener should prevent any subsequent packet listeners from
|
|
|
|
being called, and, if the listener is early, should prevent the default
|
|
|
|
behaviour from being triggered.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
keep_alive_ids_incoming = []
|
|
|
|
keep_alive_ids_outgoing = []
|
|
|
|
|
|
|
|
def handle_keep_alive_1(packet):
|
|
|
|
keep_alive_ids_incoming.append(packet.keep_alive_id)
|
|
|
|
if packet.keep_alive_id == 1:
|
|
|
|
raise IgnorePacket
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_keep_alive_1, clientbound.play.KeepAlivePacket, early=True)
|
|
|
|
|
|
|
|
def handle_keep_alive_2(packet):
|
|
|
|
keep_alive_ids_incoming.append(packet.keep_alive_id)
|
|
|
|
assert packet.keep_alive_id > 1
|
|
|
|
if packet.keep_alive_id == 2:
|
|
|
|
raise IgnorePacket
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_keep_alive_2, clientbound.play.KeepAlivePacket)
|
|
|
|
|
|
|
|
def handle_keep_alive_3(packet):
|
|
|
|
keep_alive_ids_incoming.append(packet.keep_alive_id)
|
|
|
|
assert packet.keep_alive_id == 3
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_keep_alive_3, clientbound.play.KeepAlivePacket)
|
|
|
|
|
|
|
|
def handle_outgoing_keep_alive_2(packet):
|
|
|
|
keep_alive_ids_outgoing.append(packet.keep_alive_id)
|
|
|
|
assert 2 <= packet.keep_alive_id <= 3
|
|
|
|
if packet.keep_alive_id == 2:
|
|
|
|
raise IgnorePacket
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_outgoing_keep_alive_2, serverbound.play.KeepAlivePacket,
|
|
|
|
outgoing=True, early=True)
|
|
|
|
|
|
|
|
def handle_outgoing_keep_alive_3(packet):
|
|
|
|
keep_alive_ids_outgoing.append(packet.keep_alive_id)
|
|
|
|
assert packet.keep_alive_id == 3
|
|
|
|
raise IgnorePacket
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_outgoing_keep_alive_3, serverbound.play.KeepAlivePacket,
|
|
|
|
outgoing=True)
|
|
|
|
|
|
|
|
def handle_outgoing_keep_alive_none(packet):
|
|
|
|
keep_alive_ids_outgoing.append(packet.keep_alive_id)
|
|
|
|
assert False
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_outgoing_keep_alive_none, serverbound.play.KeepAlivePacket,
|
|
|
|
outgoing=True)
|
|
|
|
|
|
|
|
def handle_disconnect(packet):
|
|
|
|
assert keep_alive_ids_incoming == [1, 2, 2, 3, 3, 3], \
|
|
|
|
'Incoming keep-alive IDs %r != %r' % \
|
|
|
|
(keep_alive_ids_incoming, [1, 2, 2, 3, 3, 3])
|
|
|
|
assert keep_alive_ids_outgoing == [2, 3, 3], \
|
|
|
|
'Outgoing keep-alive IDs %r != %r' % \
|
|
|
|
(keep_alive_ids_incoming, [2, 3, 3])
|
|
|
|
client.register_packet_listener(
|
|
|
|
handle_disconnect, clientbound.play.DisconnectPacket)
|
|
|
|
|
|
|
|
client.connect()
|
|
|
|
|
|
|
|
class client_handler_type(fake_server.FakeClientHandler):
|
|
|
|
__slots__ = '_keep_alive_ids_returned'
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwds):
|
|
|
|
super(IgnorePacketTest.client_handler_type, self).__init__(
|
|
|
|
*args, **kwds)
|
|
|
|
self._keep_alive_ids_returned = []
|
|
|
|
|
|
|
|
def handle_play_start(self):
|
|
|
|
super(IgnorePacketTest.client_handler_type, self)\
|
|
|
|
.handle_play_start()
|
|
|
|
self.write_packet(clientbound.play.KeepAlivePacket(
|
|
|
|
keep_alive_id=1))
|
|
|
|
self.write_packet(clientbound.play.KeepAlivePacket(
|
|
|
|
keep_alive_id=2))
|
|
|
|
self.write_packet(clientbound.play.KeepAlivePacket(
|
|
|
|
keep_alive_id=3))
|
2017-08-22 19:12:51 +02:00
|
|
|
self.handle_play_server_disconnect('Test complete.')
|
2017-08-22 18:50:16 +02:00
|
|
|
|
|
|
|
def handle_play_packet(self, packet):
|
|
|
|
super(IgnorePacketTest.client_handler_type, self) \
|
|
|
|
.handle_play_packet(packet)
|
|
|
|
if isinstance(packet, serverbound.play.KeepAlivePacket):
|
|
|
|
self._keep_alive_ids_returned.append(packet.keep_alive_id)
|
|
|
|
|
|
|
|
def handle_play_client_disconnect(self):
|
|
|
|
assert self._keep_alive_ids_returned == [3], \
|
|
|
|
'Returned keep-alive IDs %r != %r' % \
|
|
|
|
(self._keep_alive_ids_returned, [3])
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
2018-05-27 08:40:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
class HandleExceptionTest(ConnectTest):
|
|
|
|
ignore_extra_exceptions = True
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
message = 'Min skoldpadda ar inte snabb, men den ar en skoldpadda.'
|
|
|
|
|
2019-05-14 18:41:58 +02:00
|
|
|
@client.listener(clientbound.login.LoginSuccessPacket)
|
2018-05-27 08:40:13 +02:00
|
|
|
def handle_login_success(_packet):
|
|
|
|
raise Exception(message)
|
|
|
|
|
2020-12-04 15:36:06 +01:00
|
|
|
@client.exception_handler(early=True)
|
2019-05-14 18:41:58 +02:00
|
|
|
def handle_exception(exc, _exc_info):
|
2018-05-27 08:40:13 +02:00
|
|
|
assert isinstance(exc, Exception) and exc.args == (message,)
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
|
|
|
|
|
|
|
client.connect()
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
|
2020-12-04 15:55:39 +01:00
|
|
|
class ExceptionReconnectTest(ConnectTest):
|
|
|
|
class CustomException(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
self.phase = 0
|
|
|
|
|
|
|
|
def _start_client(self, client):
|
|
|
|
@client.listener(clientbound.play.JoinGamePacket)
|
|
|
|
def handle_join_game(packet):
|
|
|
|
if self.phase == 0:
|
|
|
|
self.phase += 1
|
|
|
|
raise self.CustomException
|
|
|
|
else:
|
|
|
|
raise fake_server.FakeServerTestSuccess
|
|
|
|
|
|
|
|
@client.exception_handler(self.CustomException, early=True)
|
|
|
|
def handle_custom_exception(exc, exc_info):
|
|
|
|
client.disconnect(immediate=True)
|
|
|
|
client.connect()
|
|
|
|
|
|
|
|
client.connect()
|
|
|
|
|
|
|
|
class client_handler_type(ConnectTest.client_handler_type):
|
|
|
|
def handle_abnormal_disconnect(self, exc):
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2018-05-29 02:14:46 +02:00
|
|
|
class VersionNegotiationEdgeCases(fake_server._FakeServerTest):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
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]
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
def test_client_protocol_unsupported(self):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
self._test_client_protocol(version=self.fake_version)
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
def test_client_protocol_unknown(self):
|
|
|
|
self._test_client_protocol(version='surprise me!')
|
|
|
|
|
|
|
|
def test_client_protocol_invalid(self):
|
|
|
|
self._test_client_protocol(version=object())
|
|
|
|
|
|
|
|
def _test_client_protocol(self, version):
|
|
|
|
with self.assertRaisesRegexp(ValueError, 'Unsupported version'):
|
|
|
|
self._test_connect(client_versions={version})
|
|
|
|
|
|
|
|
def test_server_protocol_unsupported(self, client_versions=None):
|
|
|
|
with self.assertRaisesRegexp(VersionMismatch, 'not supported'):
|
|
|
|
self._test_connect(client_versions=client_versions,
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
server_version=self.fake_version)
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
def test_server_protocol_unsupported_direct(self):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
self.test_server_protocol_unsupported({self.latest_version})
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
def test_server_protocol_disallowed(self, client_versions=None):
|
|
|
|
if client_versions is None:
|
|
|
|
client_versions = set(SUPPORTED_PROTOCOL_VERSIONS) \
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
- {self.latest_version}
|
2018-05-29 02:14:46 +02:00
|
|
|
with self.assertRaisesRegexp(VersionMismatch, 'not allowed'):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
self._test_connect(client_versions={self.earliest_version},
|
|
|
|
server_version=self.latest_version)
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
def test_server_protocol_disallowed_direct(self):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
self.test_server_protocol_disallowed({self.earliest_version})
|
2018-05-29 02:14:46 +02:00
|
|
|
|
|
|
|
def test_default_protocol_version(self, status_response=None):
|
|
|
|
if status_response is None:
|
|
|
|
status_response = '{"description": {"text": "FakeServer"}}'
|
|
|
|
|
|
|
|
class ClientHandler(fake_server.FakeClientHandler):
|
2019-05-11 08:43:08 +02:00
|
|
|
def handle_status(self, request_packet):
|
2018-05-29 02:14:46 +02:00
|
|
|
packet = clientbound.status.ResponsePacket()
|
|
|
|
packet.json_response = status_response
|
|
|
|
self.write_packet(packet)
|
|
|
|
|
|
|
|
def handle_play_start(self):
|
|
|
|
super(ClientHandler, self).handle_play_start()
|
|
|
|
raise fake_server.FakeServerDisconnect('Test complete.')
|
|
|
|
|
|
|
|
def make_connection(*args, **kwds):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
kwds['initial_version'] = self.earliest_version
|
2018-05-29 02:14:46 +02:00
|
|
|
return Connection(*args, **kwds)
|
|
|
|
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
self._test_connect(server_version=self.earliest_version,
|
2018-05-29 02:14:46 +02:00
|
|
|
client_handler_type=ClientHandler,
|
|
|
|
connection_type=make_connection)
|
|
|
|
|
|
|
|
def test_default_protocol_version_empty(self):
|
|
|
|
with self.assertRaisesRegexp(IOError, 'Invalid server status'):
|
|
|
|
self.test_default_protocol_version(status_response='{}')
|
|
|
|
|
|
|
|
def test_default_protocol_version_eof(self):
|
|
|
|
class ClientHandler(fake_server.FakeClientHandler):
|
|
|
|
def handle_status(self, request_packet):
|
|
|
|
raise fake_server.FakeServerDisconnect(
|
|
|
|
'Refusing to handle status request, for test purposes.')
|
|
|
|
|
|
|
|
def handle_play_start(self):
|
|
|
|
super(ClientHandler, self).handle_play_start()
|
|
|
|
raise fake_server.FakeServerDisconnect('Test complete.')
|
|
|
|
|
|
|
|
def make_connection(*args, **kwds):
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
kwds['initial_version'] = self.earliest_version
|
2018-05-29 02:14:46 +02:00
|
|
|
return Connection(*args, **kwds)
|
|
|
|
|
Fix: non-monotonic protocol versions are not correctly handled
After 1.16.3, Mojang started publishing snapshot, pre-release and release
candidate versions of Minecraft with protocol version numbers of the form
`(1 << 30) | n' where 'n' is a small non-negative integer increasing with each
such version; the release versions continued to use the old format. For
example, these are the last 8 published Minecraft versions as of this commit:
release 1.16.3 uses protocol version 753
pre-release 1.16.4-pre1 uses protocol version 1073741825 == (1 << 30) | 1
pre-release 1.16.4-pre2 uses protocol version 1073741826 == (1 << 30) | 2
release candidate 1.16.4-rc1 uses protocol version 1073741827 == (1 << 30) | 3
release 1.16.4 uses protocol version 754
snapshot 20w45a uses protocol version 1073741829 == (1 << 30) | 5
snapshot 20w46a uses protocol version 1073741830 == (1 << 30) | 6
snapshot 20w48a uses protocol version 1073741831 == (1 << 30) | 7
This means that protocol versions no longer increase monotonically with respect
to publication history, a property that was assumed to hold in much of
pyCraft's code relating to support of multiple protocol versions. This commit
rectifies the issue by replacing any comparison of protocol versions by their
numerical value with a comparison based on their publication time.
Newly defined is the dictionary `minecraft.PROTOCOL_VERSION_INDICES', which
maps each known protocol version to its index in the protocol chronology. As
such, the bound method `minecraft.PROTOCOL_VERSION_INDICES.get` can be used as
a key function for the built-in `sorted`, `min` and `max` functions to collate
protocol versions chronologically.
Two utility functions are provided for direct comparison of protocol versions:
`minecraft.utility.protocol_earlier` and
`minecraft.utility.protocol_earlier_eq`.
Additionally, four methods are added to the `ConnectionContext` type to ease
the most common cases where the protocol of a given context must be compared to
a given version number:
`minecraft.connection.ConnectionContext.protocol_earlier`,
`minecraft.connection.ConnectionContext.protocol_earlier_eq`,
`minecraft.connection.ConnectionContext.protocol_later` and
`minecraft.connection.ConnectionContext.protocol_later_eq`.
2020-12-02 14:30:40 +01:00
|
|
|
self._test_connect(server_version=self.earliest_version,
|
2018-05-29 02:14:46 +02:00
|
|
|
client_handler_type=ClientHandler,
|
|
|
|
connection_type=make_connection)
|