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`.
* Add multi-attribute aliases to some packets, for user convenience.
* Add support for writing PlayerListItemPacket.
* Add 'fields' attributes to manually-read/written packet classes,
implementing 'field_string' where appropriate to allow enable the
default __repr__ implementation.
* Modify data constructors where appropriate so that __repr__
implementations match their constructor protocols.
* Improve comments on type aliases within packet classes.
* Add/modify tests to cover the new functionality.
Improvements to the test suite:
* List release version names and numbers in minecraft/__init__.py.
* Make some tests, which previously ran for *all* protocol versions,
run only for release protocol versions (to improve test performance).
* Make some tests, which previously ran only for the latest protocol
version, run for all release protocol versions (to improve coverage).
* Print each protocol version being tested to the debug log, to help
identify sources of errors.
* Use the `nose-timer' plugin to show the run time of each test.
Fix errors revealed by increased test coverage:
* Fix: SoundEffectPacket.Pitch is not serialised correctly for early
protocol versions.
* Fix: handleExceptionTest finishes later than necessary because
the test overrode an exception handler used internally by
`_FakeServerTest', causing the server thread to time out after 4s.
* Add support for multiple exception handlers in `Connection'
(required for the above).
Improvements to data descriptors:
* Make syntax of property declarations more consistent/Pythonic.
* Factor the definition of several aliasing properties into the
utility methods `attribute_alias' and `multi_attribute_alias',
which construct suitable data descriptors.
* Define and use the named tuple `Direction' for (pitch, yaw) values.
This commit introduces two backward-incompatible changes which may break
existing code:
(1) `networking.packets.clientbound.play.SpawnObjectPacket.EntityType'
is no longer accessible as an attribute of the the `SpawnObjectPacket'
class: the values now depend on a `ConnectionContext`, and must be
accessed through an instance, or using `SpawnObjectPacket.field_enum'.
See the text of the `AttributeError` raised from the descriptor for
`SpawnObjectPacket.EntityType` for the full details.
(2) For some subclasses of `networking.types.Type', it is necessary to
call the methods `read_with_context' and `send_with_context' instead of
`read' and `send', supplying a `ConnectionContext' for those data types
- currently only `Position` - whose layout depends on it.