429 lines
16 KiB
Python
429 lines
16 KiB
Python
from minecraft import PRE
|
|
from minecraft.networking.packets import (
|
|
Packet, AbstractKeepAlivePacket, AbstractPluginMessagePacket
|
|
)
|
|
|
|
from minecraft.networking.types import (
|
|
FixedPoint, Integer, Angle, UnsignedByte, Byte, Boolean, UUID, Short,
|
|
VarInt, Double, Float, String, Enum, Difficulty, Long, Vector, Direction,
|
|
PositionAndLook, multi_attribute_alias, attribute_transform,
|
|
)
|
|
|
|
from .combat_event_packet import (
|
|
CombatEventPacket, EnterCombatEventPacket, EndCombatEventPacket,
|
|
DeathCombatEventPacket,
|
|
)
|
|
from .map_packet import MapPacket
|
|
from .player_list_item_packet import PlayerListItemPacket
|
|
from .player_position_and_look_packet import PlayerPositionAndLookPacket
|
|
from .spawn_object_packet import SpawnObjectPacket
|
|
from .block_change_packet import BlockChangePacket, MultiBlockChangePacket
|
|
from .explosion_packet import ExplosionPacket
|
|
from .sound_effect_packet import SoundEffectPacket
|
|
from .face_player_packet import FacePlayerPacket
|
|
from .join_game_and_respawn_packets import JoinGamePacket, RespawnPacket
|
|
|
|
|
|
# Formerly known as state_playing_clientbound.
|
|
def get_packets(context):
|
|
packets = {
|
|
KeepAlivePacket,
|
|
JoinGamePacket,
|
|
ServerDifficultyPacket,
|
|
ChatMessagePacket,
|
|
PlayerPositionAndLookPacket,
|
|
MapPacket,
|
|
PlayerListItemPacket,
|
|
DisconnectPacket,
|
|
SpawnPlayerPacket,
|
|
EntityVelocityPacket,
|
|
EntityPositionDeltaPacket,
|
|
TimeUpdatePacket,
|
|
UpdateHealthPacket,
|
|
ExplosionPacket,
|
|
SpawnObjectPacket,
|
|
BlockChangePacket,
|
|
MultiBlockChangePacket,
|
|
RespawnPacket,
|
|
PluginMessagePacket,
|
|
PlayerListHeaderAndFooterPacket,
|
|
EntityLookPacket,
|
|
ResourcePackSendPacket
|
|
}
|
|
|
|
if context.protocol_earlier_eq(47):
|
|
packets |= {
|
|
SetCompressionPacket,
|
|
}
|
|
|
|
if context.protocol_earlier(PRE | 15):
|
|
packets |= {
|
|
CombatEventPacket,
|
|
}
|
|
else:
|
|
packets |= {
|
|
EnterCombatEventPacket,
|
|
EndCombatEventPacket,
|
|
DeathCombatEventPacket,
|
|
}
|
|
|
|
if context.protocol_later_eq(94):
|
|
packets |= {
|
|
SoundEffectPacket,
|
|
}
|
|
|
|
if context.protocol_later_eq(352):
|
|
packets |= {
|
|
FacePlayerPacket
|
|
}
|
|
|
|
return packets
|
|
|
|
|
|
class KeepAlivePacket(AbstractKeepAlivePacket):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x21 if context.protocol_later_eq(755) else \
|
|
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 0x0E if context.protocol_later_eq(755) else \
|
|
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_later_eq(464) else {},
|
|
])
|
|
|
|
# These aliases declare the Enum type corresponding to each field:
|
|
Difficulty = Difficulty
|
|
|
|
|
|
class ChatMessagePacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x0F if context.protocol_later_eq(755) else \
|
|
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_later_eq(718) else {},
|
|
])
|
|
|
|
class Position(Enum):
|
|
CHAT = 0 # A player-initiated chat message.
|
|
SYSTEM = 1 # The result of running a command.
|
|
GAME_INFO = 2 # Displayed above the hotbar in vanilla clients.
|
|
|
|
|
|
class DisconnectPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x1A if context.protocol_later_eq(755) else \
|
|
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"
|
|
|
|
definition = [
|
|
{'json_data': String}]
|
|
|
|
|
|
class SetCompressionPacket(Packet):
|
|
# Note: removed between protocol versions 47 and 107.
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x03 if context.protocol_later_eq(755) else \
|
|
0x46
|
|
|
|
packet_name = "set compression"
|
|
definition = [
|
|
{'threshold': VarInt}]
|
|
|
|
|
|
class SpawnPlayerPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
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_later_eq(100)
|
|
else {'x': FixedPoint(Integer)},
|
|
{'y': Double} if context.protocol_later_eq(100)
|
|
else {'y': FixedPoint(Integer)},
|
|
{'z': Double} if context.protocol_later_eq(100)
|
|
else {'z': FixedPoint(Integer)},
|
|
{'yaw': Angle},
|
|
{'pitch': Angle},
|
|
{'current_item': Short} if context.protocol_earlier_eq(49) else {},
|
|
# TODO: read entity metadata (protocol < 550)
|
|
])
|
|
|
|
# Access the 'x', 'y', 'z' fields as a Vector tuple.
|
|
position = multi_attribute_alias(Vector, 'x', 'y', 'z')
|
|
|
|
# Access the 'yaw', 'pitch' fields as a Direction tuple.
|
|
look = multi_attribute_alias(Direction, 'yaw', 'pitch')
|
|
|
|
# Access the 'x', 'y', 'z', 'yaw', 'pitch' fields as a PositionAndLook.
|
|
# NOTE: modifying the object retrieved from this property will not change
|
|
# the packet; it can only be changed by attribute or property assignment.
|
|
position_and_look = multi_attribute_alias(
|
|
PositionAndLook, 'x', 'y', 'z', 'yaw', 'pitch')
|
|
|
|
|
|
class EntityVelocityPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x4F if context.protocol_later_eq(755) else \
|
|
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'
|
|
get_definition = staticmethod(lambda context: [
|
|
{'entity_id': VarInt},
|
|
{'velocity_x': Short},
|
|
{'velocity_y': Short},
|
|
{'velocity_z': Short}
|
|
])
|
|
|
|
|
|
class EntityPositionDeltaPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x29 if context.protocol_later_eq(755) else \
|
|
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"
|
|
|
|
@staticmethod
|
|
def get_definition(context):
|
|
delta_type = FixedPoint(Short, 12) \
|
|
if context.protocol_later_eq(106) else \
|
|
FixedPoint(Byte)
|
|
return [
|
|
{'entity_id': VarInt},
|
|
{'delta_x_float': delta_type},
|
|
{'delta_y_float': delta_type},
|
|
{'delta_z_float': delta_type},
|
|
{'on_ground': Boolean},
|
|
]
|
|
|
|
# The following transforms are retained for backward compatibility;
|
|
# they represent the delta values as fixed-point integers with 12 bits
|
|
# of fractional part, regardless of the protocol version.
|
|
delta_x = attribute_transform(
|
|
'delta_x_float', lambda x: int(x * 4096), lambda x: x / 4096)
|
|
delta_y = attribute_transform(
|
|
'delta_y_float', lambda y: int(y * 4096), lambda y: y / 4096)
|
|
delta_z = attribute_transform(
|
|
'delta_z_float', lambda z: int(z * 4096), lambda z: z / 4096)
|
|
|
|
|
|
class TimeUpdatePacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x59 if context.protocol_later_eq(PRE | 48) else \
|
|
0x58 if context.protocol_later_eq(755) else \
|
|
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"
|
|
get_definition = staticmethod(lambda context: [
|
|
{'world_age': Long},
|
|
{'time_of_day': Long},
|
|
])
|
|
|
|
|
|
class UpdateHealthPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x52 if context.protocol_later_eq(755) else \
|
|
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'
|
|
get_definition = staticmethod(lambda context: [
|
|
{'health': Float},
|
|
{'food': VarInt},
|
|
{'food_saturation': Float}
|
|
])
|
|
|
|
|
|
class PluginMessagePacket(AbstractPluginMessagePacket):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x18 if context.protocol_later_eq(755) else \
|
|
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 0x5F if context.protocol_later_eq(PRE | 48) else \
|
|
0x5E if context.protocol_later_eq(755) else \
|
|
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'
|
|
definition = [
|
|
{'header': String},
|
|
{'footer': String}]
|
|
|
|
|
|
class EntityLookPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x2B if context.protocol_later_eq(755) else \
|
|
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'
|
|
definition = [
|
|
{'entity_id': VarInt},
|
|
{'yaw': Angle},
|
|
{'pitch': Angle},
|
|
{'on_ground': Boolean}
|
|
]
|
|
|
|
|
|
class ResourcePackSendPacket(Packet):
|
|
@staticmethod
|
|
def get_id(context):
|
|
return 0x3C if context.protocol_later_eq(PRE | 15) else \
|
|
0x39 if context.protocol_later_eq(PRE | 8) else \
|
|
0x38 if context.protocol_later_eq(741) else \
|
|
0x39 if context.protocol_later_eq(721) else \
|
|
0x3A if context.protocol_later_eq(550) else \
|
|
0x39 if context.protocol_later_eq(471) else \
|
|
0x37 if context.protocol_later_eq(461) else \
|
|
0x38 if context.protocol_later_eq(451) else \
|
|
0x37 if context.protocol_later_eq(389) else \
|
|
0x36 if context.protocol_later_eq(352) else \
|
|
0x35 if context.protocol_later_eq(345) else \
|
|
0x34 if context.protocol_later_eq(336) else \
|
|
0x33 if context.protocol_later_eq(332) else \
|
|
0x34 if context.protocol_later_eq(318) else \
|
|
0x32 if context.protocol_later_eq(70) else \
|
|
0x48
|
|
|
|
packet_name = "resource pack send"
|
|
|
|
@staticmethod
|
|
def get_definition(context):
|
|
return [
|
|
{"url": String},
|
|
{"hash": String},
|
|
{"forced": Boolean} if context.protocol_later_eq(PRE | 5) else {},
|
|
{"forced_message": String}
|
|
if context.protocol_later_eq(PRE | 15) else {},
|
|
]
|