From 51570aec292f242284c3a30833c6b7c690ed0ce4 Mon Sep 17 00:00:00 2001 From: James Lyne Date: Wed, 7 Dec 2022 17:19:46 +0000 Subject: [PATCH 1/5] 1.19.3 data files --- quarry/data/data_packs/0761_1.19.3.nbt | Bin 0 -> 2692 bytes quarry/data/packets/0761_1.19.3.csv | 172 +++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 quarry/data/data_packs/0761_1.19.3.nbt create mode 100644 quarry/data/packets/0761_1.19.3.csv diff --git a/quarry/data/data_packs/0761_1.19.3.nbt b/quarry/data/data_packs/0761_1.19.3.nbt new file mode 100644 index 0000000000000000000000000000000000000000..b0116c2996d64bcc32800bcbd408a3b06fff9306 GIT binary patch literal 2692 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 literal 0 HcmV?d00001 diff --git a/quarry/data/packets/0761_1.19.3.csv b/quarry/data/packets/0761_1.19.3.csv new file mode 100644 index 0000000..c6e2f74 --- /dev/null +++ b/quarry/data/packets/0761_1.19.3.csv @@ -0,0 +1,172 @@ +protocol_mode,packet_direction,packet_name +init,upstream,handshake +play,downstream,spawn_object +play,downstream,spawn_experience_orb +play,downstream,spawn_player +play,downstream,animation +play,downstream,statistics +play,downstream,acknowledge_block_changes +play,downstream,block_break_animation +play,downstream,update_block_entity +play,downstream,block_action +play,downstream,block_change +play,downstream,boss_bar +play,downstream,server_difficulty +play,downstream,clear_titles +play,downstream,tab_complete +play,downstream,declare_commands +play,downstream,close_window +play,downstream,window_items +play,downstream,window_property +play,downstream,set_slot +play,downstream,set_cooldown +play,downstream,custom_chat_completions +play,downstream,plugin_message +play,downstream,delete_chat_message +play,downstream,disconnect +play,downstream,disguised_chat +play,downstream,entity_status +play,downstream,explosion +play,downstream,unload_chunk +play,downstream,change_game_state +play,downstream,open_horse_window +play,downstream,initialize_world_border +play,downstream,keep_alive +play,downstream,chunk_data +play,downstream,effect +play,downstream,particle +play,downstream,update_light +play,downstream,join_game +play,downstream,map +play,downstream,trade_list +play,downstream,entity_relative_move +play,downstream,entity_look_and_relative_move +play,downstream,entity_look +play,downstream,vehicle_move +play,downstream,open_book +play,downstream,open_window +play,downstream,open_sign_editor +play,downstream,ping +play,downstream,craft_recipe_response +play,downstream,player_abilities +play,downstream,chat_message +play,downstream,end_combat_event +play,downstream,enter_combat_event +play,downstream,death_combat_event +play,downstream,player_list_remove +play,downstream,player_list_item +play,downstream,face_player +play,downstream,player_position_and_look +play,downstream,unlock_recipes +play,downstream,destroy_entities +play,downstream,remove_entity_effect +play,downstream,resource_pack_send +play,downstream,respawn +play,downstream,entity_head_look +play,downstream,multi_block_change +play,downstream,select_advancement_tab +play,downstream,server_data +play,downstream,action_bar +play,downstream,world_border_center +play,downstream,world_border_lerp_size +play,downstream,world_border_size +play,downstream,world_border_warning_delay +play,downstream,world_border_warning_reach +play,downstream,camera +play,downstream,held_item_change +play,downstream,update_view_position +play,downstream,update_view_distance +play,downstream,spawn_position +play,downstream,display_scoreboard +play,downstream,entity_metadata +play,downstream,attach_entity +play,downstream,entity_velocity +play,downstream,entity_equipment +play,downstream,set_experience +play,downstream,update_health +play,downstream,scoreboard_objective +play,downstream,set_passengers +play,downstream,teams +play,downstream,update_score +play,downstream,set_simulation_distance +play,downstream,set_title_subtitle +play,downstream,time_update +play,downstream,set_title_text +play,downstream,set_title_time +play,downstream,entity_sound_effect +play,downstream,sound_effect +play,downstream,stop_sound +play,downstream,system_message +play,downstream,player_list_header_footer +play,downstream,block_metadata_response +play,downstream,collect_item +play,downstream,entity_teleport +play,downstream,advancements +play,downstream,entity_properties +play,downstream,update_enabled_features +play,downstream,entity_effect +play,downstream,declare_recipes +play,downstream,tags +play,upstream,teleport_confirm +play,upstream,block_metadata_request +play,upstream,set_difficulty +play,upstream,acknowledge_chat +play,upstream,chat_command +play,upstream,chat_message +play,upstream,client_status +play,upstream,client_settings +play,upstream,tab_complete +play,upstream,confirm_transaction +play,upstream,click_window +play,upstream,close_window +play,upstream,plugin_message +play,upstream,edit_book +play,upstream,entity_metadata_request +play,upstream,use_entity +play,upstream,generate_structure +play,upstream,keep_alive +play,upstream,lock_difficulty +play,upstream,player_position +play,upstream,player_position_and_look +play,upstream,player_look +play,upstream,player +play,upstream,vehicle_move +play,upstream,steer_boat +play,upstream,pick_item +play,upstream,craft_recipe_request +play,upstream,player_abilities +play,upstream,player_digging +play,upstream,entity_action +play,upstream,steer_vehicle +play,upstream,pong +play,upstream,chat_session_update +play,upstream,set_displayed_recipe +play,upstream,set_recipe_book_state +play,upstream,name_item +play,upstream,resource_pack_status +play,upstream,advancement_tab +play,upstream,select_trade +play,upstream,set_beacon_effect +play,upstream,held_item_change +play,upstream,update_command_block +play,upstream,update_command_block_minecart +play,upstream,creative_inventory_action +play,upstream,update_jigsaw_block +play,upstream,update_structure_block +play,upstream,update_sign +play,upstream,animation +play,upstream,spectate +play,upstream,player_block_placement +play,upstream,use_item +status,downstream,status_response +status,downstream,status_pong +status,upstream,status_request +status,upstream,status_ping +login,downstream,login_disconnect +login,downstream,login_encryption_request +login,downstream,login_success +login,downstream,login_set_compression +login,downstream,login_plugin_request +login,upstream,login_start +login,upstream,login_encryption_response +login,upstream,login_plugin_response From 25ccfb0e925b958d81b3b9659cb9fa952e29a9f9 Mon Sep 17 00:00:00 2001 From: James Lyne Date: Thu, 8 Dec 2022 18:52:19 +0000 Subject: [PATCH 2/5] 1.19.3 buffer updates --- quarry/types/buffer/__init__.py | 2 + quarry/types/buffer/v1_19.py | 95 +++++++++++++++++ quarry/types/buffer/v1_19_3.py | 177 ++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 quarry/types/buffer/v1_19_3.py diff --git a/quarry/types/buffer/__init__.py b/quarry/types/buffer/__init__.py index 81a14e6..a288864 100644 --- a/quarry/types/buffer/__init__.py +++ b/quarry/types/buffer/__init__.py @@ -9,6 +9,7 @@ class BufferUnderrun(Exception): from quarry.types.buffer.v1_14 import Buffer1_14 from quarry.types.buffer.v1_19 import Buffer1_19 from quarry.types.buffer.v1_19_1 import Buffer1_19_1 +from quarry.types.buffer.v1_19_3 import Buffer1_19_3 # Versioned buffers used after handshaking @@ -20,6 +21,7 @@ class BufferUnderrun(Exception): (477, Buffer1_14), (759, Buffer1_19), (760, Buffer1_19_1), + (761, Buffer1_19_3), ] diff --git a/quarry/types/buffer/v1_19.py b/quarry/types/buffer/v1_19.py index b2b566a..f538a7a 100644 --- a/quarry/types/buffer/v1_19.py +++ b/quarry/types/buffer/v1_19.py @@ -6,6 +6,101 @@ class Buffer1_19(Buffer1_14): + + @classmethod + def pack_global_position(cls, dimension, x, y, z): + """ + Packs a global position. + """ + + return cls.pack_string(dimension) + cls.pack_position(x, y, z) + + def unpack_global_position(self): + """ + Unpacks a global position. + """ + + return self.unpack_string(), self.unpack_position() + + @classmethod + def pack_entity_metadata(cls, metadata): + """ + Packs entity metadata. + """ + + pack_position = lambda pos: cls.pack_position(*pos) + pack_global_position = lambda pos: cls.pack_global_position(*pos) + + out = b"" + for ty_key, val in metadata.items(): + ty, key = ty_key + out += cls.pack('B', key) + out += cls.pack_varint(ty) + + if ty == 0: out += cls.pack('b', val) + elif ty == 1: out += cls.pack_varint(val) + elif ty == 2: out += cls.pack('f', val) + elif ty == 3: out += cls.pack_string(val) + elif ty == 4: out += cls.pack_chat(val) + elif ty == 5: out += cls.pack_optional(cls.pack_chat, val) + elif ty == 6: out += cls.pack_slot(**val) + elif ty == 7: out += cls.pack('?', val) + elif ty == 8: out += cls.pack_rotation(*val) + elif ty == 9: out += cls.pack_position(*val) + elif ty == 10: out += cls.pack_optional(pack_position, val) + elif ty == 11: out += cls.pack_direction(val) + elif ty == 12: out += cls.pack_optional(cls.pack_uuid, val) + elif ty == 13: out += cls.pack_block(val) + elif ty == 14: out += cls.pack_nbt(val) + elif ty == 15: out += cls.pack_particle(*val) + elif ty == 16: out += cls.pack_villager(*val) + elif ty == 17: out += cls.pack_optional_varint(val) + elif ty == 18: out += cls.pack_pose(val) + elif ty == 19: out += cls.pack_varint(val) + elif ty == 20: out += cls.pack_varint(val) + elif ty == 21: out += cls.pack_optional(pack_global_position, val) + elif ty == 22: out += cls.pack_varint(val) + else: raise ValueError("Unknown entity metadata type: %d" % ty) + out += cls.pack('B', 255) + return out + + def unpack_entity_metadata(self): + """ + Unpacks entity metadata. + """ + + metadata = {} + while True: + key = self.unpack('B') + if key == 255: + return metadata + ty = self.unpack('B') + if ty == 0: val = self.unpack('b') + elif ty == 1: val = self.unpack_varint() + elif ty == 2: val = self.unpack('f') + elif ty == 3: val = self.unpack_string() + elif ty == 4: val = self.unpack_chat() + elif ty == 5: val = self.unpack_optional(self.unpack_chat) + elif ty == 6: val = self.unpack_slot() + elif ty == 7: val = self.unpack('?') + elif ty == 8: val = self.unpack_rotation() + elif ty == 9: val = self.unpack_position() + elif ty == 10: val = self.unpack_optional(self.unpack_position) + elif ty == 11: val = self.unpack_direction() + elif ty == 12: val = self.unpack_optional(self.unpack_uuid) + elif ty == 13: val = self.unpack_block() + elif ty == 14: val = self.unpack_nbt() + elif ty == 15: val = self.unpack_particle() + elif ty == 16: val = self.unpack_villager() + elif ty == 17: val = self.unpack_optional_varint() + elif ty == 18: val = self.unpack_pose() + elif ty == 19: val = self.unpack_varint(val) + elif ty == 20: val = self.unpack_varint(val) + elif ty == 21: val = self.unpack_optional(self.unpack_global_position) + elif ty == 22: val = self.unpack_varint(val) + else: raise ValueError("Unknown entity metadata type: %d" % ty) + metadata[ty, key] = val + @classmethod def pack_player_public_key(cls, data: PlayerPublicKey): return cls.pack('Q', data.expiry) \ diff --git a/quarry/types/buffer/v1_19_3.py b/quarry/types/buffer/v1_19_3.py new file mode 100644 index 0000000..7319cda --- /dev/null +++ b/quarry/types/buffer/v1_19_3.py @@ -0,0 +1,177 @@ +from quarry.types.buffer.v1_14 import smelt_types +from quarry.types.buffer.v1_19_1 import Buffer1_19_1 + + +class Buffer1_19_3(Buffer1_19_1): + + @classmethod + def pack_entity_metadata(cls, metadata): + """ + Packs entity metadata. + """ + + pack_position = lambda pos: cls.pack_position(*pos) + pack_global_position = lambda pos: cls.pack_global_position(*pos) + + out = b"" + for ty_key, val in metadata.items(): + ty, key = ty_key + out += cls.pack('B', key) + out += cls.pack_varint(ty) + + if ty == 0: out += cls.pack('b', val) + elif ty == 1: out += cls.pack_varint(val) + elif ty == 2: out += cls.pack('q', val) + elif ty == 3: out += cls.pack('f', val) + elif ty == 4: out += cls.pack_string(val) + elif ty == 5: out += cls.pack_chat(val) + elif ty == 6: out += cls.pack_optional(cls.pack_chat, val) + elif ty == 7: out += cls.pack_slot(**val) + elif ty == 8: out += cls.pack('?', val) + elif ty == 9: out += cls.pack_rotation(*val) + elif ty == 10: out += cls.pack_position(*val) + elif ty == 11: out += cls.pack_optional(pack_position, val) + elif ty == 12: out += cls.pack_direction(val) + elif ty == 13: out += cls.pack_optional(cls.pack_uuid, val) + elif ty == 14: out += cls.pack_block(val) + elif ty == 15: out += cls.pack_nbt(val) + elif ty == 16: out += cls.pack_particle(*val) + elif ty == 17: out += cls.pack_villager(*val) + elif ty == 18: out += cls.pack_optional_varint(val) + elif ty == 19: out += cls.pack_pose(val) + elif ty == 20: out += cls.pack_varint(val) + elif ty == 21: out += cls.pack_varint(val) + elif ty == 22: out += cls.pack_optional(pack_global_position, val) + elif ty == 23: out += cls.pack_varint(val) + else: raise ValueError("Unknown entity metadata type: %d" % ty) + out += cls.pack('B', 255) + return out + + def unpack_entity_metadata(self): + """ + Unpacks entity metadata. + """ + + metadata = {} + while True: + key = self.unpack('B') + if key == 255: + return metadata + ty = self.unpack('B') + if ty == 0: val = self.unpack('b') + elif ty == 1: val = self.unpack_varint() + elif ty == 2: val = self.unpack('q') + elif ty == 3: val = self.unpack('f') + elif ty == 4: val = self.unpack_string() + elif ty == 5: val = self.unpack_chat() + elif ty == 6: val = self.unpack_optional(self.unpack_chat) + elif ty == 7: val = self.unpack_slot() + elif ty == 8: val = self.unpack('?') + elif ty == 9: val = self.unpack_rotation() + elif ty == 10: val = self.unpack_position() + elif ty == 11: val = self.unpack_optional(self.unpack_position) + elif ty == 12: val = self.unpack_direction() + elif ty == 13: val = self.unpack_optional(self.unpack_uuid) + elif ty == 14: val = self.unpack_block() + elif ty == 15: val = self.unpack_nbt() + elif ty == 16: val = self.unpack_particle() + elif ty == 17: val = self.unpack_villager() + elif ty == 18: val = self.unpack_optional_varint() + elif ty == 19: val = self.unpack_pose() + elif ty == 20: val = self.unpack_varint(val) + elif ty == 21: val = self.unpack_varint(val) + elif ty == 22: val = self.unpack_optional(self.unpack_global_position) + elif ty == 23: val = self.unpack_varint(val) + else: raise ValueError("Unknown entity metadata type: %d" % ty) + metadata[ty, key] = val + + def unpack_recipe(self): + """ + Unpacks a crafting recipe. + """ + recipe = {} + recipe['type'] = self.unpack_string() + recipe['name'] = self.unpack_string() + + if recipe['type'] == 'minecraft:crafting_shapeless': + recipe['group'] = self.unpack_string() + recipe['category'] = self.unpack_varint() # Crafting book category + recipe['ingredients'] = [ + self.unpack_ingredient() for _ in range(self.unpack_varint())] + recipe['result'] = self.unpack_slot() + + elif recipe['type'] == 'minecraft:crafting_shaped': + recipe['width'] = self.unpack_varint() + recipe['height'] = self.unpack_varint() + recipe['group'] = self.unpack_string() + recipe['category'] = self.unpack_varint() # Crafting book category + recipe['ingredients'] = [ + self.unpack_ingredient() for _ in range(recipe['width'] * + recipe['height'])] + recipe['result'] = self.unpack_slot() + elif recipe['type'] in smelt_types: + recipe['group'] = self.unpack_string() + recipe['category'] = self.unpack_varint() # Crafting book category + recipe['ingredient'] = self.unpack_ingredient() + recipe['result'] = self.unpack_slot() + recipe['experience'] = self.unpack('f') + recipe['cooking_time'] = self.unpack_varint() + + # TODO: Move to 1.14 + elif type == 'minecraft:stonecutting': + recipe['group'] = self.unpack_string() + recipe['ingredient'] = self.unpack_ingredient() + recipe['result'] = self.unpack_slot() + + # TODO: Move to 1.16 + elif type == 'minecraft:smithing': + recipe['ingredients'] = [self.unpack_ingredient(), self.unpack_ingredient()] + recipe['result'] = self.unpack_slot() + + return recipe + + @classmethod + def pack_recipe(cls, name, type, **recipe): + """ + Packs a crafting recipe. + """ + data = cls.pack_string(type) + cls.pack_string(name) + + if type == 'minecraft:crafting_shapeless': + data += cls.pack_string(recipe['group']) + data += cls.pack_varint(recipe['category']) # Crafting book category + data += cls.pack_varint(len(recipe['ingredients'])) + for ingredient in recipe['ingredients']: + data += cls.pack_ingredient(ingredient) + data += cls.pack_slot(**recipe['result']) + + elif type == 'minecraft:crafting_shaped': + data += cls.pack_varint(recipe['width']) + data += cls.pack_varint(recipe['height']) + data += cls.pack_string(recipe['group']) + data += cls.pack_varint(recipe['category']) # Crafting book category + for ingredient in recipe['ingredients']: + data += cls.pack_ingredient(ingredient) + data += cls.pack_slot(**recipe['result']) + + elif type in smelt_types: + data += cls.pack_string(recipe['group']) + data += cls.pack_varint(recipe['category']) # Crafting book category + data += cls.pack_ingredient(recipe['ingredient']) + data += cls.pack_slot(**recipe['result']) + data += cls.pack('f', recipe['experience']) + data += cls.pack_varint(recipe['cooking_time']) + + # TODO: Move to 1.14 + elif type == 'minecraft:stonecutting': + data += cls.pack_string(recipe['group']) + data += cls.pack_ingredient(recipe['ingredient']) + data += cls.pack_slot(**recipe['result']) + + # TODO: Move to 1.16 + elif type == 'minecraft:smithing': + data += cls.pack_ingredient(recipe['ingredients'][0]) + data += cls.pack_ingredient(recipe['ingredients'][1]) + data += cls.pack_slot(**recipe['result']) + + return data \ No newline at end of file From db7419f017736db248f1c51d473b21b1d81cc54c Mon Sep 17 00:00:00 2001 From: James Lyne Date: Wed, 7 Dec 2022 17:19:59 +0000 Subject: [PATCH 3/5] 1.19.3 client updates --- quarry/net/client.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/quarry/net/client.py b/quarry/net/client.py index 43e4168..5c7ac5d 100644 --- a/quarry/net/client.py +++ b/quarry/net/client.py @@ -40,13 +40,17 @@ def switch_protocol_mode(self, mode): elif mode == "login": # Send login start - # TODO: Implement signatures/1.19.1 UUID sending - if self.protocol_version >= 760: # 1.19.1+ + # TODO: Implement signature/UUID sending + if self.protocol_version >= 761: # 1.19.3+ sends optional UUID + self.send_packet("login_start", + self.buff_type.pack_string(self.factory.profile.display_name), + self.buff_type.pack("?", False)) # No UUID as we haven't implemented them yet + elif self.protocol_version >= 760: # 1.19.1 sends optional signature and uuid self.send_packet("login_start", self.buff_type.pack_string(self.factory.profile.display_name), self.buff_type.pack("?", False), # No signature as we haven't implemented them here self.buff_type.pack("?", False)) # No UUID as we haven't implemented them yet - elif self.protocol_version == 759: # 1.19 + elif self.protocol_version == 759: # 1.19 sends optional signature self.send_packet("login_start", self.buff_type.pack_string(self.factory.profile.display_name), self.buff_type.pack("?", False)) # No signature as we haven't implemented them here @@ -98,8 +102,8 @@ def auth_ok(self, data): pack_array = lambda d: self.buff_type.pack_varint( len(d), max_bits=16) + d - # 1.19+ - if self.protocol_version >= 759: + # 1.19 - 1.19.2 + if 759 <= self.protocol_version < 761: self.send_packet( "login_encryption_response", pack_array(p_shared_secret), From a4f1f6befe27993091916312794676a7da5768d1 Mon Sep 17 00:00:00 2001 From: James Lyne Date: Wed, 7 Dec 2022 17:20:03 +0000 Subject: [PATCH 4/5] 1.19.3 server updates --- quarry/net/server.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quarry/net/server.py b/quarry/net/server.py index 5516035..f987451 100644 --- a/quarry/net/server.py +++ b/quarry/net/server.py @@ -181,8 +181,8 @@ def packet_login_start(self, buff): if self.factory.online_mode: self.login_expecting = 1 - # 1.19+ may send a Mojang signed public key which needs to be verified - if self.protocol_version >= 759: + # 1.19 - 1.19.2 may send a Mojang signed public key which needs to be verified + if 759 <= self.protocol_version < 761: try: self.public_key_data = buff.unpack_optional(buff.unpack_player_public_key) except ValueError: @@ -246,8 +246,8 @@ def packet_login_encryption_response(self, buff): p_shared_secret = unpack_array(buff) salt = None - # 1.19 can now sign the verify token + a salt with the players public key, rather than encrypting the token - if self.protocol_version >= 759: + # 1.19 - 1.19.2 can now sign the verify token + a salt with the players public key, rather than encrypting the token + if 759 <= self.protocol_version < 761: if buff.unpack("?") is False: salt = buff.unpack("Q").to_bytes(8, 'big') From bea93140ec0c063ff2a08170bf7f76d2bea3b358 Mon Sep 17 00:00:00 2001 From: James Lyne Date: Wed, 7 Dec 2022 17:20:09 +0000 Subject: [PATCH 5/5] 1.19.3 example updates --- examples/server_chat_room.py | 5 ++ examples/server_chat_room_advanced.py | 80 ++++++++++++++++++++------- 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/examples/server_chat_room.py b/examples/server_chat_room.py index d658ef4..e5e67b9 100644 --- a/examples/server_chat_room.py +++ b/examples/server_chat_room.py @@ -68,9 +68,14 @@ def player_joined(self): if self.protocol_version >= 759: # 1.19 join_game.append(self.buff_type.pack("?", False)) + # Send "Join Game" packet self.send_packet("join_game", *join_game) + # 1.19.3+ Send default spawn position, required to hide Loading Terrain screen + if self.protocol_version >= 761: + self.send_packet("spawn_position", self.buff_type.pack("iii", 0, 0, 0)) + # Send "Player Position and Look" packet self.send_packet( "player_position_and_look", diff --git a/examples/server_chat_room_advanced.py b/examples/server_chat_room_advanced.py index 8100c8b..6e6c270 100644 --- a/examples/server_chat_room_advanced.py +++ b/examples/server_chat_room_advanced.py @@ -34,20 +34,16 @@ def player_joined(self): # in-game, and does some logging. ServerProtocol.player_joined(self) - # Send server data packet on 1.19+ - if self.protocol_version >= 760: - self.send_packet('server_data', - self.buff_type.pack('????', - False, # Optional description - False, # Optional favicon - False, # Disable chat previews - self.factory.online_mode)) # Enforce chat signing when in online mode - elif self.protocol_version == 759: # 1.19 lacks enforce chat signing field - self.send_packet('server_data', self.buff_type.pack('???', False, False, False)) + # Send server data + self.factory.send_server_data(self) # Send join game packet self.factory.send_join_game(self) + # 1.19.3+ Send default spawn position, required to hide Loading Terrain screen + if self.protocol_version >= 761: + self.send_packet("spawn_position", self.buff_type.pack("iii", 0, 0, 0)) + # Send "Player Position and Look" packet self.send_packet( "player_position_and_look", @@ -225,6 +221,27 @@ class ChatRoomFactory(ServerFactory): protocol = ChatRoomProtocol motd = "Chat Room Server" + def send_server_data(self, player): + # 1.19.3+ removed chat preview field + if player.protocol_version >= 761: + player.send_packet('server_data', + player.buff_type.pack('???', + False, + False, + self.online_mode)) # Enforce chat signing when in online mode + + # 1.19 added enforce chat signing field + elif player.protocol_version >= 760: + player.send_packet('server_data', + player.buff_type.pack('????', + False, + False, + False, + self.online_mode)) # Enforce chat signing when in online mode + + elif player.protocol_version == 759: + player.send_packet('server_data', self.buff_type.pack('???', False, False, False)) + def send_join_game(self, player): # Build up fields for "Join Game" packet entity_id = 0 @@ -375,10 +392,17 @@ def broadcast_player_list_add(self, added: ChatRoomProtocol): @staticmethod def send_player_list_add(player: ChatRoomProtocol, added: List[ChatRoomProtocol]): - data = [ - player.buff_type.pack_varint(0), # Action - 0 = Player add - player.buff_type.pack_varint(len(added)), # Player entry count - ] + data = [] + + # 1.19.3+ splits the player list into separate remove and update packets (which also add players) + # Update packets use a bitset to indicate which player information is being added/updated + if player.protocol_version >= 761: + data.append(player.buff_type.pack('B', 63)) # Set first 6 bits to indicate all fields are being updated + + else: # Older versions have a single packet with a varint for "action", 0 being adding a player + data.append(player.buff_type.pack_varint(0)) + + data.append(player.buff_type.pack_varint(len(added))) # Player entry count for entry in added: if entry.protocol_mode != 'play': @@ -387,12 +411,22 @@ def send_player_list_add(player: ChatRoomProtocol, added: List[ChatRoomProtocol] data.append(player.buff_type.pack_uuid(entry.uuid)) # Player UUID data.append(player.buff_type.pack_string(entry.display_name)) # Player name data.append(player.buff_type.pack_varint(0)) # Empty properties list + + # 1.19.3+ include the players public key here + if player.protocol_version >= 761: + data.append(player.buff_type.pack('?', False)) + data.append(player.buff_type.pack_varint(3)) # Gamemode + + # 1.19.3+ includes an extra field for whether to update the tab list + if player.protocol_version >= 761: + data.append(player.buff_type.pack('?', True)) + data.append(player.buff_type.pack_varint(0)) # Latency data.append(player.buff_type.pack('?', False)) # No display name - # Add signature for 1.19+ clients if it exists - if player.protocol_version >= 759: + # 1.19 - 1.19.1 include the players public key here + if 759 <= player.protocol_version < 761: data.append(player.buff_type.pack_optional(player.buff_type.pack_player_public_key, entry.public_key_data)) player.send_packet('player_list_item', *data) @@ -401,10 +435,16 @@ def send_player_list_add(player: ChatRoomProtocol, added: List[ChatRoomProtocol] def broadcast_player_list_remove(self, removed: ChatRoomProtocol): for player in self.players: if player.protocol_mode == 'play' and player != removed: - player.send_packet('player_list_item', - player.buff_type.pack_varint(4), # Action - 4 = Player remove - player.buff_type.pack_varint(1), # Player entry count - player.buff_type.pack_uuid(removed.uuid)) # Player UUID + + if player.protocol_version >= 761: # 1.19.3 has separate packet for player list removals + player.send_packet('player_list_remove', + player.buff_type.pack_varint(1), # Player entry count + player.buff_type.pack_uuid(removed.uuid)) # Player UUID + else: + player.send_packet('player_list_item', + player.buff_type.pack_varint(4), # Action - 4 = Player remove + player.buff_type.pack_varint(1), # Player entry count + player.buff_type.pack_uuid(removed.uuid)) # Player UUID def main(argv):